From cb988d68bd6e4c9ab2a51cbb6c107d6b16848d2e Mon Sep 17 00:00:00 2001 From: Luis Jesus Date: Tue, 16 Apr 2024 16:38:42 +0100 Subject: [PATCH 1/3] update dependencies --- mix.exs | 4 ++-- mix.lock | 34 +++++++++++++++++----------------- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/mix.exs b/mix.exs index b3f75e1..842f51e 100644 --- a/mix.exs +++ b/mix.exs @@ -25,12 +25,12 @@ defmodule AnalyticsElixir.Mixfile do [ {:dialyxir, "~> 1.0.0", only: [:dev], runtime: false}, {:ex_doc, "~> 0.24", only: :dev, runtime: false}, - {:hackney, "~> 1.15"}, + {:hackney, "~> 1.20"}, {:jason, ">= 1.0.0"}, {:mox, "~> 0.5", only: :test}, {:retry, "~> 0.13"}, {:telemetry, "~> 0.4.2 or ~> 1.0"}, - {:tesla, "~> 1.2"} + {:tesla, "~> 1.9"} ] end diff --git a/mix.lock b/mix.lock index 8280a91..47fdc9e 100644 --- a/mix.lock +++ b/mix.lock @@ -1,27 +1,27 @@ %{ - "certifi": {:hex, :certifi, "2.5.1", "867ce347f7c7d78563450a18a6a28a8090331e77fa02380b4a21962a65d36ee5", [:rebar3], [{:parse_trans, "~>3.3", [hex: :parse_trans, repo: "hexpm", optional: false]}], "hexpm", "805abd97539caf89ec6d4732c91e62ba9da0cda51ac462380bbd28ee697a8c42"}, + "certifi": {:hex, :certifi, "2.12.0", "2d1cca2ec95f59643862af91f001478c9863c2ac9cb6e2f89780bfd8de987329", [:rebar3], [], "hexpm", "ee68d85df22e554040cdb4be100f33873ac6051387baf6a8f6ce82272340ff1c"}, "dialyxir": {:hex, :dialyxir, "1.0.0", "6a1fa629f7881a9f5aaf3a78f094b2a51a0357c843871b8bc98824e7342d00a5", [:mix], [{:erlex, ">= 0.2.6", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "aeb06588145fac14ca08d8061a142d52753dbc2cf7f0d00fc1013f53f8654654"}, "earmark": {:hex, :earmark, "1.4.3", "364ca2e9710f6bff494117dbbd53880d84bebb692dafc3a78eb50aa3183f2bfd", [:mix], [], "hexpm", "8cf8a291ebf1c7b9539e3cddb19e9cef066c2441b1640f13c34c1d3cfc825fec"}, - "earmark_parser": {:hex, :earmark_parser, "1.4.17", "6f3c7e94170377ba45241d394389e800fb15adc5de51d0a3cd52ae766aafd63f", [:mix], [], "hexpm", "f93ac89c9feca61c165b264b5837bf82344d13bebc634cd575cb711e2e342023"}, + "earmark_parser": {:hex, :earmark_parser, "1.4.39", "424642f8335b05bb9eb611aa1564c148a8ee35c9c8a8bba6e129d51a3e3c6769", [:mix], [], "hexpm", "06553a88d1f1846da9ef066b87b57c6f605552cfbe40d20bd8d59cc6bde41944"}, "erlex": {:hex, :erlex, "0.2.6", "c7987d15e899c7a2f34f5420d2a2ea0d659682c06ac607572df55a43753aa12e", [:mix], [], "hexpm", "2ed2e25711feb44d52b17d2780eabf998452f6efda104877a3881c2f8c0c0c75"}, - "ex_doc": {:hex, :ex_doc, "0.25.5", "ac3c5425a80b4b7c4dfecdf51fa9c23a44877124dd8ca34ee45ff608b1c6deb9", [:mix], [{:earmark_parser, "~> 1.4.0", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1", [hex: :makeup_erlang, repo: "hexpm", optional: false]}], "hexpm", "688cfa538cdc146bc4291607764a7f1fcfa4cce8009ecd62de03b27197528350"}, - "hackney": {:hex, :hackney, "1.15.2", "07e33c794f8f8964ee86cebec1a8ed88db5070e52e904b8f12209773c1036085", [:rebar3], [{:certifi, "2.5.1", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "6.0.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "1.0.1", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~>1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "1.1.5", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}], "hexpm", "e0100f8ef7d1124222c11ad362c857d3df7cb5f4204054f9f0f4a728666591fc"}, + "ex_doc": {:hex, :ex_doc, "0.32.1", "21e40f939515373bcdc9cffe65f3b3543f05015ac6c3d01d991874129d173420", [:mix], [{:earmark_parser, "~> 1.4.39", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_c, ">= 0.1.1", [hex: :makeup_c, repo: "hexpm", optional: true]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1", [hex: :makeup_erlang, repo: "hexpm", optional: false]}], "hexpm", "5142c9db521f106d61ff33250f779807ed2a88620e472ac95dc7d59c380113da"}, + "hackney": {:hex, :hackney, "1.20.1", "8d97aec62ddddd757d128bfd1df6c5861093419f8f7a4223823537bad5d064e2", [:rebar3], [{:certifi, "~> 2.12.0", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "~> 6.1.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "~> 1.0.0", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~> 1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "3.4.1", [hex: :parse_trans, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "~> 1.1.0", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}, {:unicode_util_compat, "~> 0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "fe9094e5f1a2a2c0a7d10918fee36bfec0ec2a979994cff8cfe8058cd9af38e3"}, "httpoison": {:hex, :httpoison, "1.5.1", "0f55b5b673b03c5c327dac7015a67cb571b99b631acc0bc1b0b98dcd6b9f2104", [:mix], [{:hackney, "~> 1.8", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm"}, - "idna": {:hex, :idna, "6.0.0", "689c46cbcdf3524c44d5f3dde8001f364cd7608a99556d8fbd8239a5798d4c10", [:rebar3], [{:unicode_util_compat, "0.4.1", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "4bdd305eb64e18b0273864920695cb18d7a2021f31a11b9c5fbcd9a253f936e2"}, - "jason": {:hex, :jason, "1.2.0", "10043418c42d2493d0ee212d3fddd25d7ffe484380afad769a0a38795938e448", [:mix], [{:decimal, "~> 1.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "116747dbe057794c3a3e4e143b7c8390b29f634e16c78a7f59ba75bfa6852e7f"}, - "makeup": {:hex, :makeup, "1.0.5", "d5a830bc42c9800ce07dd97fa94669dfb93d3bf5fcf6ea7a0c67b2e0e4a7f26c", [:mix], [{:nimble_parsec, "~> 0.5 or ~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "cfa158c02d3f5c0c665d0af11512fed3fba0144cf1aadee0f2ce17747fba2ca9"}, - "makeup_elixir": {:hex, :makeup_elixir, "0.15.2", "dc72dfe17eb240552857465cc00cce390960d9a0c055c4ccd38b70629227e97c", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.1", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "fd23ae48d09b32eff49d4ced2b43c9f086d402ee4fd4fcb2d7fad97fa8823e75"}, - "makeup_erlang": {:hex, :makeup_erlang, "0.1.1", "3fcb7f09eb9d98dc4d208f49cc955a34218fc41ff6b84df7c75b3e6e533cc65f", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "174d0809e98a4ef0b3309256cbf97101c6ec01c4ab0b23e926a9e17df2077cbb"}, + "idna": {:hex, :idna, "6.1.1", "8a63070e9f7d0c62eb9d9fcb360a7de382448200fbbd1b106cc96d3d8099df8d", [:rebar3], [{:unicode_util_compat, "~> 0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "92376eb7894412ed19ac475e4a86f7b413c1b9fbb5bd16dccd57934157944cea"}, + "jason": {:hex, :jason, "1.4.1", "af1504e35f629ddcdd6addb3513c3853991f694921b1b9368b0bd32beb9f1b63", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "fbb01ecdfd565b56261302f7e1fcc27c4fb8f32d56eab74db621fc154604a7a1"}, + "makeup": {:hex, :makeup, "1.1.1", "fa0bc768698053b2b3869fa8a62616501ff9d11a562f3ce39580d60860c3a55e", [:mix], [{:nimble_parsec, "~> 1.2.2 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "5dc62fbdd0de44de194898b6710692490be74baa02d9d108bc29f007783b0b48"}, + "makeup_elixir": {:hex, :makeup_elixir, "0.16.2", "627e84b8e8bf22e60a2579dad15067c755531fea049ae26ef1020cad58fe9578", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.2.3 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "41193978704763f6bbe6cc2758b84909e62984c7752b3784bd3c218bb341706b"}, + "makeup_erlang": {:hex, :makeup_erlang, "0.1.5", "e0ff5a7c708dda34311f7522a8758e23bfcd7d8d8068dc312b5eb41c6fd76eba", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "94d2e986428585a21516d7d7149781480013c56e30c6a233534bedf38867a59a"}, "metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm", "69b09adddc4f74a40716ae54d140f93beb0fb8978d8636eaded0c31b6f099f16"}, - "mime": {:hex, :mime, "1.3.1", "30ce04ab3175b6ad0bdce0035cba77bba68b813d523d1aac73d9781b4d193cf8", [:mix], [], "hexpm", "6cbe761d6a0ca5a31a0931bf4c63204bceb64538e664a8ecf784a9a6f3b875f1"}, + "mime": {:hex, :mime, "2.0.5", "dc34c8efd439abe6ae0343edbb8556f4d63f178594894720607772a041b04b02", [:mix], [], "hexpm", "da0d64a365c45bc9935cc5c8a7fc5e49a0e0f9932a761c55d6c52b142780a05c"}, "mimerl": {:hex, :mimerl, "1.2.0", "67e2d3f571088d5cfd3e550c383094b47159f3eee8ffa08e64106cdf5e981be3", [:rebar3], [], "hexpm", "f278585650aa581986264638ebf698f8bb19df297f66ad91b18910dfc6e19323"}, "mox": {:hex, :mox, "0.5.2", "55a0a5ba9ccc671518d068c8dddd20eeb436909ea79d1799e2209df7eaa98b6c", [:mix], [], "hexpm", "df4310628cd628ee181df93f50ddfd07be3e5ecc30232d3b6aadf30bdfe6092b"}, - "nimble_parsec": {:hex, :nimble_parsec, "1.1.0", "3a6fca1550363552e54c216debb6a9e95bd8d32348938e13de5eda962c0d7f89", [:mix], [], "hexpm", "08eb32d66b706e913ff748f11694b17981c0b04a33ef470e33e11b3d3ac8f54b"}, - "parse_trans": {:hex, :parse_trans, "3.3.0", "09765507a3c7590a784615cfd421d101aec25098d50b89d7aa1d66646bc571c1", [:rebar3], [], "hexpm", "17ef63abde837ad30680ea7f857dd9e7ced9476cdd7b0394432af4bfc241b960"}, + "nimble_parsec": {:hex, :nimble_parsec, "1.4.0", "51f9b613ea62cfa97b25ccc2c1b4216e81df970acd8e16e8d1bdc58fef21370d", [:mix], [], "hexpm", "9c565862810fb383e9838c1dd2d7d2c437b3d13b267414ba6af33e50d2d1cf28"}, + "parse_trans": {:hex, :parse_trans, "3.4.1", "6e6aa8167cb44cc8f39441d05193be6e6f4e7c2946cb2759f015f8c56b76e5ff", [:rebar3], [], "hexpm", "620a406ce75dada827b82e453c19cf06776be266f5a67cff34e1ef2cbb60e49a"}, "poison": {:hex, :poison, "1.5.2", "560bdfb7449e3ddd23a096929fb9fc2122f709bcc758b2d5d5a5c7d0ea848910", [:mix], []}, - "retry": {:hex, :retry, "0.14.0", "751c0f6db0b5127acf346ea6f6c363ec4588320db785c62aa51776b4d280bf07", [:mix], [], "hexpm", "5c158bccf5e4de2a13d044b9930ceb7e7499c29e3fccd7c96f131a6b83a1cff3"}, - "ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.5", "6eaf7ad16cb568bb01753dbbd7a95ff8b91c7979482b95f38443fe2c8852a79b", [:make, :mix, :rebar3], [], "hexpm", "13104d7897e38ed7f044c4de953a6c28597d1c952075eb2e328bc6d6f2bfc496"}, - "telemetry": {:hex, :telemetry, "0.4.2", "2808c992455e08d6177322f14d3bdb6b625fbcfd233a73505870d8738a2f4599", [:rebar3], [], "hexpm", "2d1419bd9dda6a206d7b5852179511722e2b18812310d304620c7bd92a13fcef"}, - "tesla": {:hex, :tesla, "1.3.3", "26ae98627af5c406584aa6755ab5fc96315d70d69a24dd7f8369cfcb75094a45", [:mix], [{:castore, "~> 0.1", [hex: :castore, repo: "hexpm", optional: true]}, {:exjsx, ">= 3.0.0", [hex: :exjsx, repo: "hexpm", optional: true]}, {:fuse, "~> 2.4", [hex: :fuse, repo: "hexpm", optional: true]}, {:gun, "~> 1.3", [hex: :gun, repo: "hexpm", optional: true]}, {:hackney, "~> 1.6", [hex: :hackney, repo: "hexpm", optional: true]}, {:ibrowse, "~> 4.4.0", [hex: :ibrowse, repo: "hexpm", optional: true]}, {:jason, ">= 1.0.0", [hex: :jason, repo: "hexpm", optional: true]}, {:mime, "~> 1.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 1.0", [hex: :mint, repo: "hexpm", optional: true]}, {:poison, ">= 1.0.0", [hex: :poison, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: true]}], "hexpm", "2648f1c276102f9250299e0b7b57f3071c67827349d9173f34c281756a1b124c"}, - "unicode_util_compat": {:hex, :unicode_util_compat, "0.4.1", "d869e4c68901dd9531385bb0c8c40444ebf624e60b6962d95952775cac5e90cd", [:rebar3], [], "hexpm", "1d1848c40487cdb0b30e8ed975e34e025860c02e419cb615d255849f3427439d"}, + "retry": {:hex, :retry, "0.18.0", "dc58ebe22c95aa00bc2459f9e0c5400e6005541cf8539925af0aa027dc860543", [:mix], [], "hexpm", "9483959cc7bf69c9e576d9dfb2b678b71c045d3e6f39ab7c9aa1489df4492d73"}, + "ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.7", "354c321cf377240c7b8716899e182ce4890c5938111a1296add3ec74cf1715df", [:make, :mix, :rebar3], [], "hexpm", "fe4c190e8f37401d30167c8c405eda19469f34577987c76dde613e838bbc67f8"}, + "telemetry": {:hex, :telemetry, "1.2.1", "68fdfe8d8f05a8428483a97d7aab2f268aaff24b49e0f599faa091f1d4e7f61c", [:rebar3], [], "hexpm", "dad9ce9d8effc621708f99eac538ef1cbe05d6a874dd741de2e689c47feafed5"}, + "tesla": {:hex, :tesla, "1.9.0", "8c22db6a826e56a087eeb8cdef56889731287f53feeb3f361dec5d4c8efb6f14", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:exjsx, ">= 3.0.0", [hex: :exjsx, repo: "hexpm", optional: true]}, {:finch, "~> 0.13", [hex: :finch, repo: "hexpm", optional: true]}, {:fuse, "~> 2.4", [hex: :fuse, repo: "hexpm", optional: true]}, {:gun, ">= 1.0.0", [hex: :gun, repo: "hexpm", optional: true]}, {:hackney, "~> 1.6", [hex: :hackney, repo: "hexpm", optional: true]}, {:ibrowse, "4.4.2", [hex: :ibrowse, repo: "hexpm", optional: true]}, {:jason, ">= 1.0.0", [hex: :jason, repo: "hexpm", optional: true]}, {:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 1.0", [hex: :mint, repo: "hexpm", optional: true]}, {:msgpax, "~> 2.3", [hex: :msgpax, repo: "hexpm", optional: true]}, {:poison, ">= 1.0.0", [hex: :poison, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: true]}], "hexpm", "7c240c67e855f7e63e795bf16d6b3f5115a81d1f44b7fe4eadbf656bae0fef8a"}, + "unicode_util_compat": {:hex, :unicode_util_compat, "0.7.0", "bc84380c9ab48177092f43ac89e4dfa2c6d62b40b8bd132b1059ecc7232f9a78", [:rebar3], [], "hexpm", "25eee6d67df61960cf6a794239566599b09e17e668d3700247bc498638152521"}, } From 63d7471ef1ace261f9a24e65af82bb39d1ac42d4 Mon Sep 17 00:00:00 2001 From: Luis Jesus Date: Thu, 18 Apr 2024 16:56:41 +0100 Subject: [PATCH 2/3] feat: add support for multiple sources fix: fixes --- README.md | 45 ++++++++++++++------- lib/segment/analytics.ex | 84 ++++++++++++++++++++-------------------- lib/segment/batcher.ex | 69 ++++++++++++++++++++++----------- lib/segment/sender.ex | 42 +++++++++++++------- 4 files changed, 150 insertions(+), 90 deletions(-) diff --git a/README.md b/README.md index 296bc12..a6c3705 100644 --- a/README.md +++ b/README.md @@ -31,6 +31,12 @@ Start the Segment agent with your write_key from Segment for a HTTP API Server S Segment.start_link("YOUR_WRITE_KEY") ``` +You can optionally start the Segment agent to be able to send events to multiple sources. In that case, just provide a write key for each source name: + +```elixir +Segment.start_link(source_1: "YOUR_WRITE_KEY_S1", source_2: "YOUR_WRITE_KEY_S2") +``` + There are then two ways to call the different methods on the API. A basic way through `Segment.Analytics` functions with either the full event Struct or some helper methods (also allowing Context and Integrations to be set manually). @@ -43,79 +49,79 @@ The other way is to drop down lower and use `Segment.Http` `send` and `batch` di ### Track ```elixir -Segment.Analytics.track(user_id, event, %{property1: "", property2: ""}) +Segment.Analytics.track(source, user_id, event, %{property1: "", property2: ""}) ``` or the full way using a struct with all the possible options for the track call ```elixir %Segment.Analytics.Track{userId: "sdsds", event: "eventname", properties: %{property1: "", property2: ""}} -|> Segment.Analytics.track +|> Segment.Analytics.track(source) ``` ### Identify ```elixir -Segment.Analytics.identify(user_id, %{trait1: "", trait2: ""}) +Segment.Analytics.identify(source, user_id, %{trait1: "", trait2: ""}) ``` Or the full way using a struct with all the possible options for the identify call. ```elixir %Segment.Analytics.Identify{userId: "sdsds", traits: %{trait1: "", trait2: ""}} -|> Segment.Analytics.identify +|> Segment.Analytics.identify(source) ``` ### Screen ```elixir -Segment.Analytics.screen(user_id, name) +Segment.Analytics.screen(source, user_id, name) ``` Or the full way using a struct with all the possible options for the screen call. ```elixir %Segment.Analytics.Screen{userId: "sdsds", name: "dssd"} -|> Segment.Analytics.screen +|> Segment.Analytics.screen(source) ``` ### Alias ```elixir -Segment.Analytics.alias(user_id, previous_id) +Segment.Analytics.alias(source, user_id, previous_id) ``` Or the full way using a struct with all the possible options for the alias call. ```elixir %Segment.Analytics.Alias{userId: "sdsds", previousId: "dssd"} -|> Segment.Analytics.alias +|> Segment.Analytics.alias(source) ``` ### Group ```elixir -Segment.Analytics.group(user_id, group_id) +Segment.Analytics.group(source, user_id, group_id) ``` Or the full way using a struct with all the possible options for the group call. ```elixir %Segment.Analytics.Group{userId: "sdsds", groupId: "dssd"} -|> Segment.Analytics.group +|> Segment.Analytics.group(source) ``` ### Page ```elixir -Segment.Analytics.page(user_id, name) +Segment.Analytics.page(source, user_id, name) ``` Or the full way using a struct with all the possible options for the page call. ```elixir %Segment.Analytics.Page{userId: "sdsds", name: "dssd"} -|> Segment.Analytics.page +|> Segment.Analytics.page(source) ``` ### Using the Segment Context @@ -124,7 +130,7 @@ If you want to set the Context manually you should create a `Segment.Analytics.C ```elixir context = Segment.Analytics.Context.new(%{active: false}) -Segment.Analytics.track(user_id, event, %{property1: "", property2: ""}, context) +Segment.Analytics.track(:default, user_id, event, %{property1: "", property2: ""}, context) ``` ## Configuration @@ -155,12 +161,25 @@ This is how I add to a Phoenix project (may not be your preferred way) write_key: "2iFFnRsCfi" ``` + or + + ```elixir + config :segment, + write_keys: [source_1: "2iFFnRsCfi". source_2: "AakdKAsds"] + ``` + 3. Start the Segment GenServer in the supervised children list. In `application.ex` add to the children list: ```elixir {Segment, Application.get_env(:segment, :write_key)} ``` + or with multiple sources + + ```elixir + {Segment, Application.get_env(:segment, :write_keys)} + ``` + ## Running tests There are not many tests at the moment. if you want to run live tests on your account you need to change the config in `test.exs` to `config :segment, :send_to_http, true` and then provide your key as an environment variable. diff --git a/lib/segment/analytics.ex b/lib/segment/analytics.ex index 631118d..ea1e28b 100644 --- a/lib/segment/analytics.ex +++ b/lib/segment/analytics.ex @@ -15,10 +15,10 @@ defmodule Segment.Analytics do @doc """ Make a call to Segment with an event. Should be of type `Track, Identify, Screen, Alias, Group or Page` """ - @spec send(Segment.segment_event()) :: :ok - def send(%{__struct__: mod} = event) + @spec send(atom(), Segment.segment_event()) :: :ok + def send(source_name, %{__struct__: mod} = event) when mod in [Track, Identify, Screen, Alias, Group, Page] do - call(event) + call(event, source_name) end @doc """ @@ -27,9 +27,9 @@ defmodule Segment.Analytics do See [https://segment.com/docs/spec/track/](https://segment.com/docs/spec/track/) """ - @spec track(Segment.Analytics.Track.t()) :: :ok - def track(t = %Track{}) do - call(t) + @spec track(atom(), Segment.Analytics.Track.t()) :: :ok + def track(source_name, t = %Track{}) do + call(t, source_name) end @doc """ @@ -38,15 +38,15 @@ defmodule Segment.Analytics do See [https://segment.com/docs/spec/track/](https://segment.com/docs/spec/track/) """ - @spec track(segment_id(), String.t(), map(), Segment.Analytics.Context.t()) :: :ok - def track(user_id, event_name, properties \\ %{}, context \\ Context.new()) do + @spec track(atom(), segment_id(), String.t(), map(), Segment.Analytics.Context.t()) :: :ok + def track(source_name, user_id, event_name, properties \\ %{}, context \\ Context.new()) do %Track{ userId: user_id, event: event_name, properties: properties, context: context } - |> call + |> call(source_name) end @doc """ @@ -55,9 +55,9 @@ defmodule Segment.Analytics do See [https://segment.com/docs/spec/identify/](https://segment.com/docs/spec/identify/) """ - @spec identify(Segment.Analytics.Identify.t()) :: :ok - def identify(i = %Identify{}) do - call(i) + @spec identify(atom(), Segment.Analytics.Identify.t()) :: :ok + def identify(source_name, i = %Identify{}) do + call(i, source_name) end @doc """ @@ -65,10 +65,10 @@ defmodule Segment.Analytics do See [https://segment.com/docs/spec/identify/](https://segment.com/docs/spec/identify/) """ - @spec identify(segment_id(), map(), Segment.Analytics.Context.t()) :: :ok - def identify(user_id, traits \\ %{}, context \\ Context.new()) do + @spec identify(atom(), segment_id(), map(), Segment.Analytics.Context.t()) :: :ok + def identify(source_name, user_id, traits \\ %{}, context \\ Context.new()) do %Identify{userId: user_id, traits: traits, context: context} - |> call + |> call(source_name) end @doc """ @@ -77,9 +77,9 @@ defmodule Segment.Analytics do See [https://segment.com/docs/spec/screen/](https://segment.com/docs/spec/screen/) """ - @spec screen(Segment.Analytics.Screen.t()) :: :ok - def screen(s = %Screen{}) do - call(s) + @spec screen(atom(), Segment.Analytics.Screen.t()) :: :ok + def screen(source_name, s = %Screen{}) do + call(s, source_name) end @doc """ @@ -87,15 +87,15 @@ defmodule Segment.Analytics do See [https://segment.com/docs/spec/screen/](https://segment.com/docs/spec/screen/) """ - @spec screen(segment_id(), String.t(), map(), Segment.Analytics.Context.t()) :: :ok - def screen(user_id, screen_name \\ "", properties \\ %{}, context \\ Context.new()) do + @spec screen(atom(), segment_id(), String.t(), map(), Segment.Analytics.Context.t()) :: :ok + def screen(source_name, user_id, screen_name \\ "", properties \\ %{}, context \\ Context.new()) do %Screen{ userId: user_id, name: screen_name, properties: properties, context: context } - |> call + |> call(source_name) end @doc """ @@ -103,9 +103,9 @@ defmodule Segment.Analytics do See [https://segment.com/docs/spec/alias/](https://segment.com/docs/spec/alias/) """ - @spec alias(Segment.Analytics.Alias.t()) :: :ok - def alias(a = %Alias{}) do - call(a) + @spec alias(atom(), Segment.Analytics.Alias.t()) :: :ok + def alias(source_name, a = %Alias{}) do + call(a, source_name) end @doc """ @@ -113,10 +113,10 @@ defmodule Segment.Analytics do See [https://segment.com/docs/spec/alias/](https://segment.com/docs/spec/alias/) """ - @spec alias(segment_id(), segment_id(), Segment.Analytics.Context.t()) :: :ok - def alias(user_id, previous_id, context \\ Context.new()) do + @spec alias(atom(), segment_id(), segment_id(), Segment.Analytics.Context.t()) :: :ok + def alias(source_name, user_id, previous_id, context \\ Context.new()) do %Alias{userId: user_id, previousId: previous_id, context: context} - |> call + |> call(source_name) end @doc """ @@ -124,9 +124,9 @@ defmodule Segment.Analytics do See [https://segment.com/docs/spec/group/](https://segment.com/docs/spec/group/) """ - @spec group(Segment.Analytics.Group.t()) :: :ok - def group(g = %Group{}) do - call(g) + @spec group(atom(), Segment.Analytics.Group.t()) :: :ok + def group(source_name, g = %Group{}) do + call(g, source_name) end @doc """ @@ -135,10 +135,10 @@ defmodule Segment.Analytics do See [https://segment.com/docs/spec/group/](https://segment.com/docs/spec/group/) """ - @spec group(segment_id(), segment_id(), map(), Segment.Analytics.Context.t()) :: :ok - def group(user_id, group_id, traits \\ %{}, context \\ Context.new()) do + @spec group(atom(), segment_id(), segment_id(), map(), Segment.Analytics.Context.t()) :: :ok + def group(source_name, user_id, group_id, traits \\ %{}, context \\ Context.new()) do %Group{userId: user_id, groupId: group_id, traits: traits, context: context} - |> call + |> call(source_name) end @doc """ @@ -146,9 +146,9 @@ defmodule Segment.Analytics do See [https://segment.com/docs/spec/page/](https://segment.com/docs/spec/page/) """ - @spec page(Segment.Analytics.Page.t()) :: :ok - def page(p = %Page{}) do - call(p) + @spec page(atom(), Segment.Analytics.Page.t()) :: :ok + def page(source_name, p = %Page{}) do + call(p, source_name) end @doc """ @@ -156,14 +156,14 @@ defmodule Segment.Analytics do See [https://segment.com/docs/spec/page/](https://segment.com/docs/spec/page/) """ - @spec page(segment_id(), String.t(), map(), Segment.Analytics.Context.t()) :: :ok - def page(user_id, page_name \\ "", properties \\ %{}, context \\ Context.new()) do + @spec page(atom(), segment_id(), String.t(), map(), Segment.Analytics.Context.t()) :: :ok + def page(source_name, user_id, page_name \\ "", properties \\ %{}, context \\ Context.new()) do %Page{userId: user_id, name: page_name, properties: properties, context: context} - |> call + |> call(source_name) end - @spec call(Segment.segment_event()) :: :ok - def call(event) do - Segment.Config.service().call(event) + @spec call(Segment.segment_event(), atom()) :: :ok + def call(event, source_name) do + Segment.Config.service().call(event, source_name) end end diff --git a/lib/segment/batcher.ex b/lib/segment/batcher.ex index d3948cb..5f5f4ff 100644 --- a/lib/segment/batcher.ex +++ b/lib/segment/batcher.ex @@ -26,9 +26,18 @@ defmodule Segment.Analytics.Batcher do Start the `Segment.Analytics.Batcher` GenServer with an Segment HTTP Source API Write Key """ @spec start_link(String.t()) :: GenServer.on_start() - def start_link(api_key) do - client = Segment.Http.client(api_key) - GenServer.start_link(__MODULE__, {client, :queue.new()}, name: __MODULE__) + def start_link(args) do + clients = + case args do + api_key when is_bitstring(api_key) -> + [default: Segment.Http.client(api_key)] + + args when is_list(args) -> + Enum.map(args, fn {name, api_key} -> {name, Segment.Http.client(api_key)} end) + end + + queues = Enum.map(clients, fn {name, _} -> {name, :queue.new()} end) + GenServer.start_link(__MODULE__, {clients, queues}, name: __MODULE__) end @doc """ @@ -36,9 +45,18 @@ defmodule Segment.Analytics.Batcher do for testing purposes to override the Adapter with a Mock. """ @spec start_link(String.t(), Segment.Http.adapter()) :: GenServer.on_start() - def start_link(api_key, adapter) do - client = Segment.Http.client(api_key, adapter) - GenServer.start_link(__MODULE__, {client, :queue.new()}, name: __MODULE__) + def start_link(args, adapter) do + clients = + case args do + api_key when is_bitstring(api_key) -> + [default: Segment.Http.client(api_key, adapter)] + + args when is_list(args) -> + Enum.map(args, fn {name, api_key} -> {name, Segment.Http.client(api_key)} end) + end + + queues = Enum.map(clients, fn {name, _} -> {name, :queue.new()} end) + GenServer.start_link(__MODULE__, {clients, queues}, name: __MODULE__) end # client @@ -47,9 +65,9 @@ defmodule Segment.Analytics.Batcher do This event will be queued and sent later in a batch. """ @spec call(Segment.segment_event()) :: :ok - def call(%{__struct__: mod} = event) + def call(%{__struct__: mod} = event, client_name \\ :default) when mod in [Track, Identify, Screen, Alias, Group, Page] do - enqueue(event) + enqueue(event, client_name) end @doc """ @@ -69,26 +87,33 @@ defmodule Segment.Analytics.Batcher do end @impl true - def handle_cast({:enqueue, event}, {client, queue}) do - {:noreply, {client, :queue.in(event, queue)}} + def handle_cast({:enqueue, event, client_name}, {clients, queues}) do + {:noreply, {clients, Keyword.put(queues, client_name, :queue.in(event, queues[client_name]))}} end @impl true - def handle_call(:flush, _from, {client, queue}) do - items = :queue.to_list(queue) - if length(items) > 0, do: Segment.Http.batch(client, items) - {:reply, :ok, {client, :queue.new()}} + def handle_call(:flush, _from, {clients, queues}) do + # flush all queues + Enum.each(clients, fn {name, client} -> + {items, _queue} = extract_batch(queues[name], :queue.len(queues[name])) + if length(items) > 0, do: Segment.Http.batch(client, items) + end) + + {:reply, :ok, {clients, Enum.map(queues, fn {name, _} -> {name, :queue.new()} end)}} end @impl true - def handle_info(:process_batch, {client, queue}) do - length = :queue.len(queue) - {items, queue} = extract_batch(queue, length) - - if length(items) > 0, do: Segment.Http.batch(client, items) + def handle_info(:process_batch, {clients, queues}) do + # process all queues and update queues variable + queues = + Enum.map(clients, fn {name, client} -> + {items, queue} = extract_batch(queues[name], :queue.len(queues[name])) + if length(items) > 0, do: Segment.Http.batch(client, items) + {name, queue} + end) schedule_batch_send() - {:noreply, {client, queue}} + {:noreply, {clients, queues}} end def handle_info({:ssl_closed, _msg}, state), do: {:no_reply, state} @@ -98,8 +123,8 @@ defmodule Segment.Analytics.Batcher do Process.send_after(self(), :process_batch, Segment.Config.batch_every_ms()) end - defp enqueue(event) do - GenServer.cast(__MODULE__, {:enqueue, event}) + defp enqueue(event, client_name) do + GenServer.cast(__MODULE__, {:enqueue, event, client_name}) end defp extract_batch(queue, 0), diff --git a/lib/segment/sender.ex b/lib/segment/sender.ex index 21119ac..50ef3ca 100644 --- a/lib/segment/sender.ex +++ b/lib/segment/sender.ex @@ -13,9 +13,17 @@ defmodule Segment.Analytics.Sender do Start the `Segment.Analytics.Sender` GenServer with an Segment HTTP Source API Write Key """ @spec start_link(String.t()) :: GenServer.on_start() - def start_link(api_key) do - client = Segment.Http.client(api_key) - GenServer.start_link(__MODULE__, client, name: __MODULE__) + def start_link(args) do + clients = + case args do + api_key when is_bitstring(api_key) -> + [default: Segment.Http.client(api_key)] + + args when is_list(args) -> + Enum.map(args, fn {name, api_key} -> {name, Segment.Http.client(api_key)} end) + end + + GenServer.start_link(__MODULE__, clients, name: __MODULE__) end @doc """ @@ -23,9 +31,17 @@ defmodule Segment.Analytics.Sender do for testing purposes to override the Adapter with a Mock. """ @spec start_link(String.t(), Segment.Http.adapter()) :: GenServer.on_start() - def start_link(api_key, adapter) do - client = Segment.Http.client(api_key, adapter) - GenServer.start_link(__MODULE__, {client, :queue.new()}, name: __MODULE__) + def start_link(args, adapter) do + clients = + case args do + api_key when is_bitstring(api_key) -> + [default: Segment.Http.client(api_key, adapter)] + + args when is_list(args) -> + Enum.map(args, fn {name, api_key} -> {name, Segment.Http.client(api_key)} end) + end + + GenServer.start_link(__MODULE__, clients, name: __MODULE__) end # client @@ -34,9 +50,9 @@ defmodule Segment.Analytics.Sender do This event will be sent immediately and asynchronously """ @spec call(Segment.segment_event()) :: :ok - def call(%{__struct__: mod} = event) + def call(%{__struct__: mod} = event, client_name \\ :default) when mod in [Track, Identify, Screen, Alias, Group, Page] do - callp(event) + callp(event, client_name) end # GenServer Callbacks @@ -47,13 +63,13 @@ defmodule Segment.Analytics.Sender do end @impl true - def handle_cast({:send, event}, client) do - Task.start_link(fn -> Segment.Http.send(client, event) end) - {:noreply, client} + def handle_cast({:send, event, client_name}, clients) do + Task.start_link(fn -> Segment.Http.send(clients[client_name], event) end) + {:noreply, clients} end # Helpers - defp callp(event) do - GenServer.cast(__MODULE__, {:send, event}) + defp callp(event, client_name) do + GenServer.cast(__MODULE__, {:send, event, client_name}) end end From 420ddcb0907df153744980c7ae08945ad9a39783 Mon Sep 17 00:00:00 2001 From: Luis Jesus Date: Thu, 18 Apr 2024 17:35:16 +0100 Subject: [PATCH 3/3] chore: bump version --- mix.exs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mix.exs b/mix.exs index 842f51e..c99fe27 100644 --- a/mix.exs +++ b/mix.exs @@ -2,7 +2,7 @@ defmodule AnalyticsElixir.Mixfile do use Mix.Project @source_url "https://github.com/stueccles/analytics-elixir" - @version "0.2.7" + @version "0.3.0" def project do [