diff --git a/CMakeLists.txt b/CMakeLists.txt index 48b05be48d2..371d2e2c149 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1269,6 +1269,7 @@ if(gRPC_BUILD_TESTS) add_dependencies(buildtests_cxx unknown_frame_bad_client_test) add_dependencies(buildtests_cxx uri_parser_test) add_dependencies(buildtests_cxx useful_test) + add_dependencies(buildtests_cxx uuid_v4_test) add_dependencies(buildtests_cxx validation_errors_test) add_dependencies(buildtests_cxx varint_test) if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX) @@ -22125,6 +22126,44 @@ target_link_libraries(useful_test ) +endif() +if(gRPC_BUILD_TESTS) + +add_executable(uuid_v4_test + src/core/lib/gprpp/uuid_v4.cc + test/core/gprpp/uuid_v4_test.cc + third_party/googletest/googletest/src/gtest-all.cc + third_party/googletest/googlemock/src/gmock-all.cc +) +target_compile_features(uuid_v4_test PUBLIC cxx_std_14) +target_include_directories(uuid_v4_test + PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/include + ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR} + ${_gRPC_RE2_INCLUDE_DIR} + ${_gRPC_SSL_INCLUDE_DIR} + ${_gRPC_UPB_GENERATED_DIR} + ${_gRPC_UPB_GRPC_GENERATED_DIR} + ${_gRPC_UPB_INCLUDE_DIR} + ${_gRPC_XXHASH_INCLUDE_DIR} + ${_gRPC_ZLIB_INCLUDE_DIR} + third_party/googletest/googletest/include + third_party/googletest/googletest + third_party/googletest/googlemock/include + third_party/googletest/googlemock + ${_gRPC_PROTO_GENS_DIR} +) + +target_link_libraries(uuid_v4_test + ${_gRPC_BASELIB_LIBRARIES} + ${_gRPC_PROTOBUF_LIBRARIES} + ${_gRPC_ZLIB_LIBRARIES} + ${_gRPC_ALLTARGETS_LIBRARIES} + grpc_test_util +) + + endif() if(gRPC_BUILD_TESTS) diff --git a/build_autogenerated.yaml b/build_autogenerated.yaml index 00c8b65bef1..8533b98e880 100644 --- a/build_autogenerated.yaml +++ b/build_autogenerated.yaml @@ -12453,6 +12453,18 @@ targets: - absl/strings:strings - absl/types:variant uses_polling: false +- name: uuid_v4_test + gtest: true + build: test + language: c++ + headers: + - src/core/lib/gprpp/uuid_v4.h + src: + - src/core/lib/gprpp/uuid_v4.cc + - test/core/gprpp/uuid_v4_test.cc + deps: + - grpc_test_util + uses_polling: false - name: validation_errors_test gtest: true build: test diff --git a/src/core/BUILD b/src/core/BUILD index 88ddc0d17cf..b67320be39f 100644 --- a/src/core/BUILD +++ b/src/core/BUILD @@ -939,6 +939,15 @@ grpc_cc_library( ], ) +grpc_cc_library( + name = "uuid_v4", + srcs = ["lib/gprpp/uuid_v4.cc"], + external_deps = ["absl/strings:str_format"], + language = "c++", + public_hdrs = ["lib/gprpp/uuid_v4.h"], + deps = ["//:gpr"], +) + grpc_cc_library( name = "handshaker_factory", language = "c++", @@ -5382,7 +5391,10 @@ grpc_cc_library( hdrs = [ "ext/filters/logging/logging_sink.h", ], - external_deps = ["absl/strings"], + external_deps = [ + "absl/numeric:int128", + "absl/strings", + ], language = "c++", visibility = [ "//src/cpp/ext/gcp:__subpackages__", @@ -5403,7 +5415,9 @@ grpc_cc_library( "ext/filters/logging/logging_filter.h", ], external_deps = [ + "absl/numeric:int128", "absl/random", + "absl/random:distributions", "absl/status:statusor", "absl/strings", "absl/types:optional", diff --git a/src/core/ext/filters/logging/logging_filter.cc b/src/core/ext/filters/logging/logging_filter.cc index 108f3e24d8f..513a8c5e12a 100644 --- a/src/core/ext/filters/logging/logging_filter.cc +++ b/src/core/ext/filters/logging/logging_filter.cc @@ -26,14 +26,15 @@ #include #include #include -#include #include #include #include #include #include +#include "absl/numeric/int128.h" #include "absl/random/random.h" +#include "absl/random/uniform_int_distribution.h" #include "absl/status/statusor.h" #include "absl/strings/numbers.h" #include "absl/strings/str_cat.h" @@ -80,9 +81,9 @@ namespace { LoggingSink* g_logging_sink = nullptr; -uint64_t GetCallId() { +absl::uint128 GetCallId() { thread_local absl::InsecureBitGen gen; - return absl::Uniform(gen, 0u, std::numeric_limits::max()); + return absl::uniform_int_distribution()(gen); } class MetadataEncoder { @@ -330,7 +331,7 @@ class CallData { entry->is_sampled = tracer->IsSampled(); } } - uint64_t call_id_; + absl::uint128 call_id_; uint32_t sequence_id_ = 0; std::string service_name_; std::string method_name_; diff --git a/src/core/ext/filters/logging/logging_sink.h b/src/core/ext/filters/logging/logging_sink.h index 74e5930bc65..685668ffab0 100644 --- a/src/core/ext/filters/logging/logging_sink.h +++ b/src/core/ext/filters/logging/logging_sink.h @@ -26,6 +26,7 @@ #include #include +#include "absl/numeric/int128.h" #include "absl/strings/string_view.h" #include "src/core/lib/gprpp/time.h" @@ -91,7 +92,7 @@ class LoggingSink { uint32_t ip_port = 0; }; - uint64_t call_id = 0; + absl::uint128 call_id = 0; uint64_t sequence_id = 0; EventType type = LoggingSink::Entry::EventType::kUnkown; Logger logger = LoggingSink::Entry::Logger::kUnkown; diff --git a/src/core/lib/gprpp/uuid_v4.cc b/src/core/lib/gprpp/uuid_v4.cc new file mode 100644 index 00000000000..ee98556f94e --- /dev/null +++ b/src/core/lib/gprpp/uuid_v4.cc @@ -0,0 +1,39 @@ +// +// +// Copyright 2023 gRPC authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// + +#include + +#include "src/core/lib/gprpp/uuid_v4.h" + +#include + +#include "absl/strings/str_format.h" + +namespace grpc_core { + +std::string GenerateUUIDv4(uint64_t hi, uint64_t lo) { + uint32_t time_low = hi >> 32; + uint16_t time_mid = hi >> 16; + uint16_t time_hi_and_version = (hi & 0x0fff) | 0x4000; + uint16_t clock_seq_hi_low = ((lo >> 48) & 0x3fff) | 0x8000; + uint64_t node = lo & 0xffffffffffff; + return absl::StrFormat("%08x-%04x-%04x-%04x-%012x", time_low, time_mid, + time_hi_and_version, clock_seq_hi_low, node); +} + +} // namespace grpc_core diff --git a/src/core/lib/gprpp/uuid_v4.h b/src/core/lib/gprpp/uuid_v4.h new file mode 100644 index 00000000000..fbedb762bbe --- /dev/null +++ b/src/core/lib/gprpp/uuid_v4.h @@ -0,0 +1,36 @@ +// +// +// Copyright 2023 gRPC authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// + +#ifndef GRPC_SRC_CORE_LIB_GPRPP_UUID_V4_H +#define GRPC_SRC_CORE_LIB_GPRPP_UUID_V4_H + +#include + +#include + +#include + +namespace grpc_core { + +// Generates string in the UUIDv4 form. \a hi and \a lo are expected to be +// random numbers. +std::string GenerateUUIDv4(uint64_t hi, uint64_t lo); + +} // namespace grpc_core + +#endif // GRPC_SRC_CORE_LIB_GPRPP_UUID_V4_H diff --git a/src/cpp/ext/gcp/BUILD b/src/cpp/ext/gcp/BUILD index fc579a0eb4a..03374a44fa7 100644 --- a/src/cpp/ext/gcp/BUILD +++ b/src/cpp/ext/gcp/BUILD @@ -107,6 +107,7 @@ grpc_cc_library( ], external_deps = [ "absl/base:core_headers", + "absl/numeric:int128", "absl/strings", "absl/strings:str_format", "absl/types:optional", @@ -130,6 +131,7 @@ grpc_cc_library( "//src/core:json", "//src/core:logging_sink", "//src/core:time", + "//src/core:uuid_v4", ], ) diff --git a/src/cpp/ext/gcp/observability_logging_sink.cc b/src/cpp/ext/gcp/observability_logging_sink.cc index 15d85d9c25f..e286b5341bb 100644 --- a/src/cpp/ext/gcp/observability_logging_sink.cc +++ b/src/cpp/ext/gcp/observability_logging_sink.cc @@ -27,9 +27,9 @@ #include +#include "absl/numeric/int128.h" #include "absl/strings/escaping.h" #include "absl/strings/match.h" -#include "absl/strings/str_cat.h" #include "absl/strings/str_format.h" #include "absl/types/optional.h" #include "google/api/monitored_resource.pb.h" @@ -48,6 +48,7 @@ #include "src/core/lib/event_engine/default_event_engine.h" #include "src/core/lib/gprpp/env.h" #include "src/core/lib/gprpp/time.h" +#include "src/core/lib/gprpp/uuid_v4.h" #include "src/core/lib/json/json.h" #include "src/cpp/ext/filters/census/open_census_call_tracer.h" @@ -207,7 +208,8 @@ void PeerToJsonStructProto(LoggingSink::Entry::Address peer, void EntryToJsonStructProto(LoggingSink::Entry entry, ::google::protobuf::Struct* json_payload) { (*json_payload->mutable_fields())["callId"].set_string_value( - absl::StrCat(entry.call_id)); + grpc_core::GenerateUUIDv4(absl::Uint128High64(entry.call_id), + absl::Uint128Low64(entry.call_id))); (*json_payload->mutable_fields())["sequenceId"].set_number_value( entry.sequence_id); (*json_payload->mutable_fields())["type"].set_string_value( diff --git a/test/core/gprpp/BUILD b/test/core/gprpp/BUILD index a9eedbcee9e..2a290eb5518 100644 --- a/test/core/gprpp/BUILD +++ b/test/core/gprpp/BUILD @@ -444,3 +444,18 @@ grpc_cc_test( "//test/core/util:grpc_test_util", ], ) + +grpc_cc_test( + name = "uuid_v4_test", + srcs = ["uuid_v4_test.cc"], + external_deps = [ + "gtest", + ], + language = "C++", + uses_event_engine = False, + uses_polling = False, + deps = [ + "//src/core:uuid_v4", + "//test/core/util:grpc_test_util", + ], +) diff --git a/test/core/gprpp/uuid_v4_test.cc b/test/core/gprpp/uuid_v4_test.cc new file mode 100644 index 00000000000..e970d54ebce --- /dev/null +++ b/test/core/gprpp/uuid_v4_test.cc @@ -0,0 +1,35 @@ +// Copyright 2023 gRPC authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "src/core/lib/gprpp/uuid_v4.h" + +#include "gtest/gtest.h" + +namespace grpc_core { + +namespace { + +TEST(UUIDv4Test, Basic) { + EXPECT_EQ(GenerateUUIDv4(0, 0), "00000000-0000-4000-8000-000000000000"); + EXPECT_EQ(GenerateUUIDv4(0x0123456789abcdef, 0x0123456789abcdef), + "01234567-89ab-4def-8123-456789abcdef"); +} + +} // namespace +} // namespace grpc_core + +int main(int argc, char** argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/test/cpp/ext/gcp/observability_logging_sink_test.cc b/test/cpp/ext/gcp/observability_logging_sink_test.cc index 774ab7fa90c..ab0ba4db8cd 100644 --- a/test/cpp/ext/gcp/observability_logging_sink_test.cc +++ b/test/cpp/ext/gcp/observability_logging_sink_test.cc @@ -337,7 +337,7 @@ TEST(EntryToJsonStructTest, ClientHeader) { "fields {\n" " key: \"callId\"\n" " value {\n" - " string_value: \"1234\"\n" + " string_value: \"00000000-0000-4000-8000-0000000004d2\"\n" " }\n" "}\n" "fields {\n" @@ -458,7 +458,7 @@ TEST(EntryToJsonStructTest, ServerHeader) { "fields {\n" " key: \"callId\"\n" " value {\n" - " string_value: \"1234\"\n" + " string_value: \"00000000-0000-4000-8000-0000000004d2\"\n" " }\n" "}\n" "fields {\n" @@ -568,7 +568,7 @@ TEST(EntryToJsonStructTest, ClientMessage) { "fields {\n" " key: \"callId\"\n" " value {\n" - " string_value: \"1234\"\n" + " string_value: \"00000000-0000-4000-8000-0000000004d2\"\n" " }\n" "}\n" "fields {\n" @@ -678,7 +678,7 @@ TEST(EntryToJsonStructTest, ServerMessage) { "fields {\n" " key: \"callId\"\n" " value {\n" - " string_value: \"1234\"\n" + " string_value: \"00000000-0000-4000-8000-0000000004d2\"\n" " }\n" "}\n" "fields {\n" @@ -786,7 +786,7 @@ TEST(EntryToJsonStructTest, ClientHalfClose) { "fields {\n" " key: \"callId\"\n" " value {\n" - " string_value: \"1234\"\n" + " string_value: \"00000000-0000-4000-8000-0000000004d2\"\n" " }\n" "}\n" "fields {\n" @@ -882,7 +882,7 @@ TEST(EntryToJsonStructTest, ServerTrailer) { "fields {\n" " key: \"callId\"\n" " value {\n" - " string_value: \"1234\"\n" + " string_value: \"00000000-0000-4000-8000-0000000004d2\"\n" " }\n" "}\n" "fields {\n" @@ -990,7 +990,7 @@ TEST(EntryToJsonStructTest, Cancel) { "fields {\n" " key: \"callId\"\n" " value {\n" - " string_value: \"1234\"\n" + " string_value: \"00000000-0000-4000-8000-0000000004d2\"\n" " }\n" "}\n" "fields {\n" diff --git a/tools/distrib/fix_build_deps.py b/tools/distrib/fix_build_deps.py index 42f001c61ed..3731546aac5 100755 --- a/tools/distrib/fix_build_deps.py +++ b/tools/distrib/fix_build_deps.py @@ -82,10 +82,14 @@ EXTERNAL_DEPS = { 'absl/memory', 'absl/meta/type_traits.h': 'absl/meta:type_traits', + 'absl/numeric/int128.h': + 'absl/numeric:int128', 'absl/random/random.h': 'absl/random', 'absl/random/distributions.h': 'absl/random:distributions', + 'absl/random/uniform_int_distribution.h': + 'absl/random:distributions', 'absl/status/status.h': 'absl/status', 'absl/status/statusor.h': diff --git a/tools/run_tests/generated/tests.json b/tools/run_tests/generated/tests.json index 6a7876956b2..7ddbd1c1614 100644 --- a/tools/run_tests/generated/tests.json +++ b/tools/run_tests/generated/tests.json @@ -8357,6 +8357,30 @@ ], "uses_polling": false }, + { + "args": [], + "benchmark": false, + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "exclude_iomgrs": [], + "flaky": false, + "gtest": true, + "language": "c++", + "name": "uuid_v4_test", + "platforms": [ + "linux", + "mac", + "posix", + "windows" + ], + "uses_polling": false + }, { "args": [], "benchmark": false,