From f3c55eba9da59042a96e683f841060674519520b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20Ka=CC=88fer?= Date: Fri, 11 Jul 2014 13:55:18 -0700 Subject: [PATCH 1/2] add logging facility and check logs in tests --- Makefile | 8 +-- common.gypi | 10 +++ include/llmr/platform/event.hpp | 53 +++++++++++++++ include/llmr/platform/log.hpp | 69 ++++++++++++++++++++ scripts/run_tests.sh | 4 +- src/platform/event.cpp | 46 +++++++++++++ src/platform/log.cpp | 7 ++ test/fixtures/fixture_log.cpp | 42 ++++++++++++ test/fixtures/fixture_log.hpp | 66 +++++++++++++++++++ test/fixtures/fixture_request.cpp | 6 +- test/fixtures/styles/line-color.info.json | 18 ++++- test/fixtures/styles/road-width.info.json | 31 +++++++-- test/fixtures/styles/world-aa.info.json | 5 +- test/fixtures/styles/world-no-aa.info.json | 6 +- test/fixtures/tiles/13-4401-2687.vector.pbf | Bin 0 -> 97260 bytes test/headless.cpp | 68 +++++++++++++++++-- test/test.gyp | 2 + 17 files changed, 418 insertions(+), 23 deletions(-) create mode 100644 include/llmr/platform/event.hpp create mode 100644 include/llmr/platform/log.hpp create mode 100644 src/platform/event.cpp create mode 100644 src/platform/log.cpp create mode 100644 test/fixtures/fixture_log.cpp create mode 100644 test/fixtures/fixture_log.hpp create mode 100644 test/fixtures/tiles/13-4401-2687.vector.pbf diff --git a/Makefile b/Makefile index 13af0f4ba..70d706afa 100644 --- a/Makefile +++ b/Makefile @@ -25,11 +25,11 @@ build/test/Makefile: src common config.gypi test/test.gyp deps/run_gyp test/test.gyp --depth=. -Goutput_dir=.. --generator-output=./build/test -f make test: build/test/Makefile - $(MAKE) -C build/test BUILDTYPE=$(BUILDTYPE) V=$(V) test + $(MAKE) -C build/test BUILDTYPE=Testing V=$(V) test test/%: build/test/Makefile - $(MAKE) -C build/test BUILDTYPE=$(BUILDTYPE) V=$(V) $* - (cd build/$(BUILDTYPE) && exec ./test_$*) + $(MAKE) -C build/test BUILDTYPE=Testing V=$(V) $* + (cd build/Testing && exec ./test_$*) # build Mac OS X project for Xcode xtest: config.gypi clear_xcode_cache node @@ -42,7 +42,7 @@ xtest: config.gypi clear_xcode_cache node # Builds the linux app with make. This is also used by Travis CI linux: config.gypi linux/llmr-app.gyp node deps/run_gyp linux/llmr-app.gyp --depth=. -Goutput_dir=.. --generator-output=./build/linux -f make - $(MAKE) -C build/linux BUILDTYPE=$(BUILDTYPE) V=$(V) linuxapp + $(MAKE) -C build/linux BUILDTYPE=Testing V=$(V) linuxapp # Executes the Linux binary run-linux: linux diff --git a/common.gypi b/common.gypi index a9567d4d3..a38a279ef 100644 --- a/common.gypi +++ b/common.gypi @@ -33,6 +33,16 @@ 'DEAD_CODE_STRIPPING': 'YES', 'GCC_INLINES_ARE_PRIVATE_EXTERN': 'YES' } + }, + 'Testing': { + 'cflags_cc': [ '-O3' ], + 'defines': [ 'NDEBUG', 'TESTING' ], + 'xcode_settings': { + 'GCC_OPTIMIZATION_LEVEL': '3', + 'GCC_GENERATE_DEBUGGING_SYMBOLS': 'NO', + 'DEAD_CODE_STRIPPING': 'YES', + 'GCC_INLINES_ARE_PRIVATE_EXTERN': 'YES' + } } } } diff --git a/include/llmr/platform/event.hpp b/include/llmr/platform/event.hpp new file mode 100644 index 000000000..2f5633c07 --- /dev/null +++ b/include/llmr/platform/event.hpp @@ -0,0 +1,53 @@ +#ifndef LLMR_PLATFORM_EVENT +#define LLMR_PLATFORM_EVENT + +#include +#include + +namespace llmr { + +enum class EventSeverity : uint8_t { + Debug, + Info, + Test, + Warning, + Error, +}; + +EventSeverity parseEventSeverity(const char *name); +::std::ostream& operator<<(::std::ostream& os, EventSeverity eventSeverity); + +enum class Event : uint8_t { + ParseStyle, + ParseTile, + Render, + HttpRequest, +}; + +Event parseEvent(const char *name); +::std::ostream& operator<<(::std::ostream& os, Event event); + +constexpr EventSeverity enabledEventSeverities[] = { +#if DEBUG + EventSeverity::Debug, +#endif + +#if TESTING + EventSeverity::Test, +#endif + + EventSeverity::Info, + EventSeverity::Warning, + EventSeverity::Error, +}; + +/* enabled event classes */ +constexpr Event enabledEvents[] = { + Event::ParseStyle, + Event::ParseTile, + Event::HttpRequest, +}; + +} + +#endif diff --git a/include/llmr/platform/log.hpp b/include/llmr/platform/log.hpp new file mode 100644 index 000000000..48c88a1fd --- /dev/null +++ b/include/llmr/platform/log.hpp @@ -0,0 +1,69 @@ +#ifndef LLMR_PLATFORM_LOG +#define LLMR_PLATFORM_LOG + +#include "event.hpp" + +#include +#include + +namespace llmr { + +class LogBackend { +public: + virtual inline ~LogBackend() = default; + virtual void record(EventSeverity severity, Event event, const std::string &msg) = 0; + virtual void record(EventSeverity severity, Event event, int64_t code) = 0; + virtual void record(EventSeverity severity, Event event, int64_t code, const std::string &msg) = 0; +}; + +class Log { +private: + template + constexpr static bool includes(const T e, T const *l, const size_t i = 0) { + return i >= sizeof l ? false : *(l + i) == e ? true : includes(e, l, i + 1); + } + +public: + template + static inline void Debug(Event event, Args&& ...args) { + Record(EventSeverity::Debug, event, ::std::forward(args)...); + } + + template + static inline void Info(Event event, Args&& ...args) { + Record(EventSeverity::Info, event, ::std::forward(args)...); + } + + template + static inline void Warning(Event event, Args&& ...args) { + Record(EventSeverity::Warning, event, ::std::forward(args)...); + } + + template + static inline void Error(Event event, Args&& ...args) { + Record(EventSeverity::Error, event, ::std::forward(args)...); + } + + template + static inline void Record(EventSeverity severity, Event event, Args&& ...args) { + if (includes(severity, enabledEventSeverities) && + includes(event, enabledEvents)) { + if (Backend) { + Backend->record(severity, event, ::std::forward(args)...); + } + } + } + + template + static inline const T &Set(Args&& ...args) { + Backend = ::std::unique_ptr(new T(::std::forward(args)...)); + return *dynamic_cast(Backend.get()); + } + +private: + static std::unique_ptr Backend; +}; + +} + +#endif diff --git a/scripts/run_tests.sh b/scripts/run_tests.sh index be65356ba..716594824 100755 --- a/scripts/run_tests.sh +++ b/scripts/run_tests.sh @@ -3,9 +3,7 @@ set -e set -o pipefail -BUILDTYPE="${BUILDTYPE:-Release}" - -cd build/${BUILDTYPE} +cd build/Testing for TEST in ./test_* ; do ${TEST} diff --git a/src/platform/event.cpp b/src/platform/event.cpp new file mode 100644 index 000000000..674bdbc8a --- /dev/null +++ b/src/platform/event.cpp @@ -0,0 +1,46 @@ +#include + +#include + +namespace llmr { + +EventSeverity parseEventSeverity(const char *name) { + if (strcmp(name, "DEBUG") == 0) return EventSeverity::Debug; + if (strcmp(name, "INFO") == 0) return EventSeverity::Info; + if (strcmp(name, "TEST") == 0) return EventSeverity::Test; + if (strcmp(name, "WARNING") == 0) return EventSeverity::Warning; + if (strcmp(name, "ERROR") == 0) return EventSeverity::Error; + return EventSeverity(-1); +} + +::std::ostream& operator<<(::std::ostream& os, EventSeverity eventSeverity) { + switch (eventSeverity) { + case EventSeverity::Debug: return os << "DEBUG"; + case EventSeverity::Info: return os << "INFO"; + case EventSeverity::Test: return os << "TEST"; + case EventSeverity::Warning: return os << "WARNING"; + case EventSeverity::Error: return os << "ERROR"; + default: return os << "UNKNOWN"; + } +} + +Event parseEvent(const char *name) { + if (strcmp(name, "ParseStyle") == 0) return Event::ParseStyle; + if (strcmp(name, "ParseTile") == 0) return Event::ParseTile; + if (strcmp(name, "Render") == 0) return Event::Render; + if (strcmp(name, "HttpRequest") == 0) return Event::HttpRequest; + return Event(-1); +} + +::std::ostream& operator<<(::std::ostream& os, Event event) { + switch (event) { + case Event::ParseStyle: return os << "ParseStyle"; + case Event::ParseTile: return os << "ParseTile"; + case Event::Render: return os << "Render"; + case Event::HttpRequest: return os << "HttpRequest"; + default: return os << "Unknown"; + } +} + + +} diff --git a/src/platform/log.cpp b/src/platform/log.cpp new file mode 100644 index 000000000..7974e5ed86 --- /dev/null +++ b/src/platform/log.cpp @@ -0,0 +1,7 @@ +#include + +namespace llmr { + +std::unique_ptr Log::Backend; + +} diff --git a/test/fixtures/fixture_log.cpp b/test/fixtures/fixture_log.cpp new file mode 100644 index 000000000..d260927b5 --- /dev/null +++ b/test/fixtures/fixture_log.cpp @@ -0,0 +1,42 @@ +#include "fixture_log.hpp" + +#include + +namespace llmr { + +size_t FixtureLogBackend::count(const LogMessage &message) const { + size_t count = 0; + for (const LogMessage &msg : messages) { + if (msg == message) { + count++; + msg.checked = true; + } + } + return count; +} + +std::vector FixtureLogBackend::unchecked() const { + std::vector unchecked; + for (const LogMessage &msg : messages) { + if (!msg.checked) { + unchecked.push_back(msg); + } + } + return unchecked; +} + +::std::ostream& operator<<(::std::ostream& os, const std::vector& messages) { + for (const FixtureLogBackend::LogMessage &message : messages) { + os << "- " << message; + } + return os; +} + +::std::ostream& operator<<(::std::ostream& os, const FixtureLogBackend::LogMessage& message) { + os << "[\"" << message.severity.get() << "\", \"" << message.event.get(); + if (message.code) os << "\", " << message.code.get(); + if (message.msg) os << ", \"" << message.msg.get(); + return os << "\"]" << std::endl; +} + +} \ No newline at end of file diff --git a/test/fixtures/fixture_log.hpp b/test/fixtures/fixture_log.hpp new file mode 100644 index 000000000..befba8b2c --- /dev/null +++ b/test/fixtures/fixture_log.hpp @@ -0,0 +1,66 @@ +#ifndef LLMR_TEST_FIXTURE_LOG +#define LLMR_TEST_FIXTURE_LOG + +#include + +#include + +#include + +namespace llmr { + +class FixtureLogBackend : public LogBackend { +public: + struct LogMessage { + inline LogMessage(EventSeverity severity, Event event, int64_t code, const std::string &msg) + : severity(severity), event(event), code(code), msg(msg) {} + inline LogMessage(EventSeverity severity, Event event, int64_t code) + : severity(severity), event(event), code(code) {} + inline LogMessage(EventSeverity severity, Event event, const std::string &msg) + : severity(severity), event(event), msg(msg) {} + inline LogMessage(EventSeverity severity, Event event) + : severity(severity), event(event) {} + + inline bool operator==(const LogMessage &rhs) const { + return (!severity || !rhs.severity || severity.get() == rhs.severity.get()) && + (!event || !rhs.event || event.get() == rhs.event.get()) && + (!code || !rhs.code || code.get() == rhs.code.get()) && + (!msg || !rhs.msg || msg.get() == rhs.msg.get()); + } + + const boost::optional severity; + const boost::optional event; + const boost::optional code; + const boost::optional msg; + + mutable bool checked = false; + }; + + inline ~FixtureLogBackend() = default; + + void record(EventSeverity severity, Event event, const std::string &msg) { + messages.emplace_back(severity, event, msg); + } + + void record(EventSeverity severity, Event event, int64_t code) { + messages.emplace_back(severity, event, code); + } + + void record(EventSeverity severity, Event event, int64_t code, const std::string &msg) { + messages.emplace_back(severity, event, code, msg); + } + + size_t count(const LogMessage &message) const; + std::vector unchecked() const; + +public: + std::vector messages; +}; + +::std::ostream& operator<<(::std::ostream& os, const std::vector& messages); +::std::ostream& operator<<(::std::ostream& os, const FixtureLogBackend::LogMessage& message); + + +} + +#endif diff --git a/test/fixtures/fixture_request.cpp b/test/fixtures/fixture_request.cpp index 8bf1e282b..c2e209bc6 100644 --- a/test/fixtures/fixture_request.cpp +++ b/test/fixtures/fixture_request.cpp @@ -1,6 +1,7 @@ #include #include #include +#include const std::string base_directory = []{ std::string fn = __FILE__; @@ -40,7 +41,7 @@ platform::request_http(const std::string &url, if (err < 0) { req->res->code = err; req->res->error_message = uv_strerror(err); - fprintf(stderr, "[WARNING] fixture request: %s\n", uv_strerror(err)); + Log::Warning(Event::HttpRequest, err, url + ": " + uv_strerror(err)); req->complete(); return req; } @@ -90,7 +91,8 @@ platform::request_http(const std::string &url, req->res->body.swap(body); req->res->code = 200; - fprintf(stderr, "[INFO] fixture request completed: %s\n", clean_url.c_str()); + // fprintf(stderr, "[INFO] fixture request completed: %s\n", clean_url.c_str()); + Log::Info(Event::HttpRequest, 200, url); req->complete(); return req; diff --git a/test/fixtures/styles/line-color.info.json b/test/fixtures/styles/line-color.info.json index 03e33581d..d9be88b10 100644 --- a/test/fixtures/styles/line-color.info.json +++ b/test/fixtures/styles/line-color.info.json @@ -2,12 +2,26 @@ "default": { "zoom": 14, "center": [52.499167, 13.418056], - "height": 256 + "height": 256, + "log": [ + [1, "INFO", "HttpRequest", 200, "tiles/14-8803-5375.vector.pbf"], + [1, "INFO", "HttpRequest", 200, "tiles/14-8802-5375.vector.pbf"], + [1, "INFO", "HttpRequest", 200, "tiles/14-8803-5374.vector.pbf"], + [1, "INFO", "HttpRequest", 200, "tiles/14-8802-5374.vector.pbf"], + [4, "INFO", "HttpRequest"] + ] }, "colored": { "zoom": 14, "center": [52.499167, 13.418056], "height": 256, - "classes": ["colored"] + "classes": ["colored"], + "log": [ + [1, "INFO", "HttpRequest", 200, "tiles/14-8803-5375.vector.pbf"], + [1, "INFO", "HttpRequest", 200, "tiles/14-8802-5375.vector.pbf"], + [1, "INFO", "HttpRequest", 200, "tiles/14-8803-5374.vector.pbf"], + [1, "INFO", "HttpRequest", 200, "tiles/14-8802-5374.vector.pbf"], + [4, "INFO", "HttpRequest"] + ] } } diff --git a/test/fixtures/styles/road-width.info.json b/test/fixtures/styles/road-width.info.json index 0c7033e4e..0094f715c 100644 --- a/test/fixtures/styles/road-width.info.json +++ b/test/fixtures/styles/road-width.info.json @@ -2,21 +2,44 @@ "z13.9": { "zoom": 13.9, "center": [52.499167, 13.418056], - "height": 256 + "height": 256, + "log": [ + [1, "INFO", "HttpRequest", 200, "tiles/13-4401-2687.vector.pbf"], + [1, "INFO", "HttpRequest"] + ] }, "z14.0": { "zoom": 14, "center": [52.499167, 13.418056], - "height": 256 + "height": 256, + "log": [ + [1, "INFO", "HttpRequest", 200, "tiles/14-8803-5375.vector.pbf"], + [1, "INFO", "HttpRequest", 200, "tiles/14-8802-5375.vector.pbf"], + [1, "INFO", "HttpRequest", 200, "tiles/14-8803-5374.vector.pbf"], + [1, "INFO", "HttpRequest", 200, "tiles/14-8802-5374.vector.pbf"], + [4, "INFO", "HttpRequest"] + ] }, "z14.1": { "zoom": 14.1, "center": [52.499167, 13.418056], - "height": 256 + "height": 256, + "log": [ + [1, "INFO", "HttpRequest", 200, "tiles/14-8803-5375.vector.pbf"], + [1, "INFO", "HttpRequest", 200, "tiles/14-8802-5375.vector.pbf"], + [1, "INFO", "HttpRequest", 200, "tiles/14-8803-5374.vector.pbf"], + [1, "INFO", "HttpRequest", 200, "tiles/14-8802-5374.vector.pbf"], + [4, "INFO", "HttpRequest"] + ] }, "z14.2": { "zoom": 14.2, "center": [52.499167, 13.418056], - "height": 256 + "height": 256, + "log": [ + [1, "INFO", "HttpRequest", 200, "tiles/14-8803-5374.vector.pbf"], + [1, "INFO", "HttpRequest", 200, "tiles/14-8802-5374.vector.pbf"], + [2, "INFO", "HttpRequest"] + ] } } diff --git a/test/fixtures/styles/world-aa.info.json b/test/fixtures/styles/world-aa.info.json index 3a61efdd1..e5e123dce 100644 --- a/test/fixtures/styles/world-aa.info.json +++ b/test/fixtures/styles/world-aa.info.json @@ -1,6 +1,9 @@ { "plain": { "center": [0, 0], - "zoom": 0 + "zoom": 0, + "log": [ + [ 1, "INFO", "HttpRequest", 200, "tiles/0-0-0.vector.pbf" ] + ] } } diff --git a/test/fixtures/styles/world-no-aa.info.json b/test/fixtures/styles/world-no-aa.info.json index 3a61efdd1..f5bc0c146 100644 --- a/test/fixtures/styles/world-no-aa.info.json +++ b/test/fixtures/styles/world-no-aa.info.json @@ -1,6 +1,10 @@ { "plain": { "center": [0, 0], - "zoom": 0 + "zoom": 0, + "log": [ + [1, "INFO", "HttpRequest", 200, "tiles/0-0-0.vector.pbf"], + [1, "INFO", "HttpRequest"] + ] } } diff --git a/test/fixtures/tiles/13-4401-2687.vector.pbf b/test/fixtures/tiles/13-4401-2687.vector.pbf new file mode 100644 index 0000000000000000000000000000000000000000..f2165b8fe58cfea42e2386e66a9d8e77bef96e0c GIT binary patch literal 97260 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

aW|3f%pq71~k+K8ny>6LQmC~jZdt|8Q)NG$I`h= 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 literal 0 HcmV?d00001 diff --git a/test/headless.cpp b/test/headless.cpp index 97a5e581a..fac38f9fd 100644 --- a/test/headless.cpp +++ b/test/headless.cpp @@ -9,6 +9,8 @@ #include "../common/headless_view.hpp" +#include "./fixtures/fixture_log.hpp" + #include const std::string base_directory = []{ @@ -20,10 +22,12 @@ const std::string base_directory = []{ class HeadlessTest : public ::testing::TestWithParam {}; TEST_P(HeadlessTest, render) { + using namespace llmr; + const std::string &base = GetParam(); - const std::string style = llmr::util::read_file(base_directory + "/" + base + ".style.json"); - const std::string info = llmr::util::read_file(base_directory + "/" + base + ".info.json"); + const std::string style = util::read_file(base_directory + "/" + base + ".style.json"); + const std::string info = util::read_file(base_directory + "/" + base + ".info.json"); // Parse settings. rapidjson::Document doc; @@ -32,10 +36,12 @@ TEST_P(HeadlessTest, render) { ASSERT_EQ(true, doc.IsObject()); // Setup OpenGL - llmr::HeadlessView view; - llmr::Map map(view); + HeadlessView view; + Map map(view); for (auto it = doc.MemberBegin(), end = doc.MemberEnd(); it != end; it++) { + const FixtureLogBackend &log = Log::Set(); + const std::string name { it->name.GetString(), it->name.GetStringLength() }; const rapidjson::Value &value = it->value; ASSERT_EQ(true, value.IsObject()); @@ -74,8 +80,58 @@ TEST_P(HeadlessTest, render) { const std::unique_ptr pixels(new uint32_t[width * height]); glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels.get()); - const std::string image = llmr::util::compress_png(width, height, pixels.get(), true); - llmr::util::write_file(actual_image, image); + const std::string image = util::compress_png(width, height, pixels.get(), true); + util::write_file(actual_image, image); + + if (value.HasMember("log")) { + const rapidjson::Value &js_log = value["log"]; + ASSERT_EQ(true, js_log.IsArray()); + for (rapidjson::SizeType i = 0; i < js_log.Size(); i++) { + const rapidjson::Value &js_entry = js_log[i]; + ASSERT_EQ(true, js_entry.IsArray()); + if (js_entry.Size() == 5) { + const uint32_t count = js_entry[rapidjson::SizeType(0)].GetUint(); + const FixtureLogBackend::LogMessage message { + parseEventSeverity(js_entry[rapidjson::SizeType(1)].GetString()), + parseEvent(js_entry[rapidjson::SizeType(2)].GetString()), + js_entry[rapidjson::SizeType(3)].GetInt64(), + js_entry[rapidjson::SizeType(4)].GetString() + }; + ASSERT_EQ(count, log.count(message)) << "Message: " << message << "Full Log: " << std::endl << log.messages; + } else if (js_entry.Size() == 4) { + const uint32_t count = js_entry[rapidjson::SizeType(0)].GetUint(); + if (js_entry[rapidjson::SizeType(3)].IsString()) { + const FixtureLogBackend::LogMessage message { + parseEventSeverity(js_entry[rapidjson::SizeType(1)].GetString()), + parseEvent(js_entry[rapidjson::SizeType(2)].GetString()), + js_entry[rapidjson::SizeType(3)].GetString() + }; + ASSERT_EQ(count, log.count(message)) << "Message: " << message << "Full Log: " << std::endl << log.messages; + } else { + const FixtureLogBackend::LogMessage message { + parseEventSeverity(js_entry[rapidjson::SizeType(1)].GetString()), + parseEvent(js_entry[rapidjson::SizeType(2)].GetString()), + js_entry[rapidjson::SizeType(3)].GetInt64() + }; + ASSERT_EQ(count, log.count(message)) << "Message: " << message << "Full Log: " << std::endl << log.messages; + } + } else if (js_entry.Size() == 3) { + const uint32_t count = js_entry[rapidjson::SizeType(0)].GetUint(); + const FixtureLogBackend::LogMessage message { + parseEventSeverity(js_entry[rapidjson::SizeType(1)].GetString()), + parseEvent(js_entry[rapidjson::SizeType(2)].GetString()) + }; + ASSERT_EQ(count, log.count(message)) << "Message: " << message << "Full Log: " << std::endl << log.messages; + } else { + FAIL(); + } + } + } + + const auto &unchecked = log.unchecked(); + if (unchecked.size()) { + std::cerr << "Unchecked Log Messages (" << base << "/" << name << "): " << std::endl << unchecked; + } } } diff --git a/test/test.gyp b/test/test.gyp index bb4bfc759..c6869fd47 100644 --- a/test/test.gyp +++ b/test/test.gyp @@ -151,6 +151,8 @@ "../common/headless_view.hpp", "../common/headless_view.cpp", "./fixtures/fixture_request.cpp", + "./fixtures/fixture_log.hpp", + "./fixtures/fixture_log.cpp", ], "dependencies": [ "../deps/gtest/gtest.gyp:gtest", From 7ffe4a7858bc5d071b87612bdaa19d8eaf29045c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20Ka=CC=88fer?= Date: Fri, 11 Jul 2014 14:34:17 -0700 Subject: [PATCH 2/2] add nslog and stderr log backends --- common/nslog_log.hpp | 20 +++++++++++++++++ common/nslog_log.mm | 24 +++++++++++++++++++++ common/stderr_log.cpp | 20 +++++++++++++++++ common/stderr_log.hpp | 20 +++++++++++++++++ include/llmr/platform/event.hpp | 3 +++ ios/mapbox-gl-cocoa | 2 +- linux/main.cpp | 5 ++++- macosx/llmr-app.gyp | 2 ++ macosx/main.mm | 7 +++--- src/platform/event.cpp | 38 +++++++++++++++++++++------------ 10 files changed, 122 insertions(+), 19 deletions(-) create mode 100644 common/nslog_log.hpp create mode 100644 common/nslog_log.mm create mode 100644 common/stderr_log.cpp create mode 100644 common/stderr_log.hpp diff --git a/common/nslog_log.hpp b/common/nslog_log.hpp new file mode 100644 index 000000000..d4ea6f6ea --- /dev/null +++ b/common/nslog_log.hpp @@ -0,0 +1,20 @@ +#ifndef LLMR_COMMON_NSLOG_LOG +#define LLMR_COMMON_NSLOG_LOG + +#include + +namespace llmr { + +class NSLogBackend : public LogBackend { +public: + inline ~NSLogBackend() = default; + + void record(EventSeverity severity, Event event, const std::string &msg); + void record(EventSeverity severity, Event event, int64_t code); + void record(EventSeverity severity, Event event, int64_t code, const std::string &msg); +}; + + +} + +#endif diff --git a/common/nslog_log.mm b/common/nslog_log.mm new file mode 100644 index 000000000..eed0810ae --- /dev/null +++ b/common/nslog_log.mm @@ -0,0 +1,24 @@ +#include "nslog_log.hpp" + +#import + +namespace llmr { + +void NSLogBackend::record(EventSeverity severity, Event event, const std::string &msg) { + NSLog(@"[%s] %s: %@", stringifyEventSeverity(severity), stringifyEvent(event), + [[NSString alloc] initWithBytes:msg.data() + length:msg.size() + encoding:NSUTF8StringEncoding]); +} + +void NSLogBackend::record(EventSeverity severity, Event event, int64_t code) { + NSLog(@"[%s] %s: (%lld)", stringifyEventSeverity(severity), stringifyEvent(event), code); +} + +void NSLogBackend::record(EventSeverity severity, Event event, int64_t code, const std::string &msg) { + NSLog(@"[%s] %s: (%lld) %@", stringifyEventSeverity(severity), stringifyEvent(event), code, + [[NSString alloc] initWithBytes:msg.data() + length:msg.size() + encoding:NSUTF8StringEncoding]); +} +} diff --git a/common/stderr_log.cpp b/common/stderr_log.cpp new file mode 100644 index 000000000..b3b1fea33 --- /dev/null +++ b/common/stderr_log.cpp @@ -0,0 +1,20 @@ +#include "stderr_log.hpp" + +#include + +namespace llmr { + +void StderrLogBackend::record(EventSeverity severity, Event event, const std::string &msg) { + std::cerr << "[" << severity << "] " << event << ": " << msg << std::endl; +} + +void StderrLogBackend::record(EventSeverity severity, Event event, int64_t code) { + std::cerr << "[" << severity << "] " << event << ": (" << code << ")" << std::endl; +} + +void StderrLogBackend::record(EventSeverity severity, Event event, int64_t code, const std::string &msg) { + std::cerr << "[" << severity << "] " << event << ": (" << code << ") " << msg << std::endl; + +} + +} diff --git a/common/stderr_log.hpp b/common/stderr_log.hpp new file mode 100644 index 000000000..32b6850cb --- /dev/null +++ b/common/stderr_log.hpp @@ -0,0 +1,20 @@ +#ifndef LLMR_COMMON_STDERR_LOG +#define LLMR_COMMON_STDERR_LOG + +#include + +namespace llmr { + +class StderrLogBackend : public LogBackend { +public: + inline ~StderrLogBackend() = default; + + void record(EventSeverity severity, Event event, const std::string &msg); + void record(EventSeverity severity, Event event, int64_t code); + void record(EventSeverity severity, Event event, int64_t code, const std::string &msg); +}; + + +} + +#endif diff --git a/include/llmr/platform/event.hpp b/include/llmr/platform/event.hpp index 2f5633c07..930f79fac 100644 --- a/include/llmr/platform/event.hpp +++ b/include/llmr/platform/event.hpp @@ -15,9 +15,11 @@ enum class EventSeverity : uint8_t { }; EventSeverity parseEventSeverity(const char *name); +const char *stringifyEventSeverity(EventSeverity eventSeverity); ::std::ostream& operator<<(::std::ostream& os, EventSeverity eventSeverity); enum class Event : uint8_t { + Setup, ParseStyle, ParseTile, Render, @@ -25,6 +27,7 @@ enum class Event : uint8_t { }; Event parseEvent(const char *name); +const char *stringifyEvent(Event event); ::std::ostream& operator<<(::std::ostream& os, Event event); constexpr EventSeverity enabledEventSeverities[] = { diff --git a/ios/mapbox-gl-cocoa b/ios/mapbox-gl-cocoa index e16b737da..9d403d2ce 160000 --- a/ios/mapbox-gl-cocoa +++ b/ios/mapbox-gl-cocoa @@ -1 +1 @@ -Subproject commit e16b737daaf9ecd2a02f7ccc61a590e9df8b2050 +Subproject commit 9d403d2cefcd63797a3da2c67d4b653e287aeec5 diff --git a/linux/main.cpp b/linux/main.cpp index 889a246c2..11a21880f 100644 --- a/linux/main.cpp +++ b/linux/main.cpp @@ -8,6 +8,7 @@ #include "../common/settings_json.hpp" #include "../common/glfw_view.hpp" +#include "../common/stderr_log.hpp" GLFWView *view = nullptr; @@ -22,6 +23,8 @@ void quit_handler(int) { } int main(int argc, char *argv[]) { + llmr::Log::Set(); + int fullscreen_flag = 0; const struct option long_options[] = { @@ -63,7 +66,7 @@ int main(int argc, char *argv[]) { // Set access token if present const char *token = getenv("MAPBOX_ACCESS_TOKEN"); if (token == nullptr) { - fprintf(stderr, "[WARNING] no access token set. mapbox.com tiles won't work.\n"); + llmr::Log::Warning(llmr::Event::Setup, "no access token set. mapbox.com tiles won't work."); } else { map.setAccessToken(std::string(token)); } diff --git a/macosx/llmr-app.gyp b/macosx/llmr-app.gyp index 02319da94..139cb744c 100644 --- a/macosx/llmr-app.gyp +++ b/macosx/llmr-app.gyp @@ -16,6 +16,8 @@ '../common/glfw_view.cpp', '../common/foundation_request.h', '../common/foundation_request.mm', + '../common/nslog_log.hpp', + '../common/nslog_log.mm', ], 'product_extension': 'app', 'mac_bundle': 1, diff --git a/macosx/main.mm b/macosx/main.mm index 3b01df04e..f72476cde 100644 --- a/macosx/main.mm +++ b/macosx/main.mm @@ -1,9 +1,12 @@ #include "../common/settings_nsuserdefaults.hpp" #include "../common/glfw_view.hpp" +#include "../common/nslog_log.hpp" #import int main() { + llmr::Log::Set(); + GLFWView view; llmr::Map map(view); @@ -16,7 +19,7 @@ int main() { // Set access token if present const char *token = getenv("MAPBOX_ACCESS_TOKEN"); if (token == nullptr) { - fprintf(stderr, "[WARNING] no access token set. mapbox.com tiles won't work.\n"); + llmr::Log::Warning(llmr::Event::Setup, "no access token set. mapbox.com tiles won't work."); } else { map.setAccessToken(std::string(token)); } @@ -28,8 +31,6 @@ int main() { error:nil]; map.setStyleJSON((std::string)[json cStringUsingEncoding:[NSString defaultCStringEncoding]]); - // fprintf(stderr, "lon: %f, lat: %f, zoom: %f, angle: %f, debug: %d\n", settings.l) - int ret = view.run(); // Save settings diff --git a/src/platform/event.cpp b/src/platform/event.cpp index 674bdbc8a..8d5507423 100644 --- a/src/platform/event.cpp +++ b/src/platform/event.cpp @@ -13,18 +13,23 @@ EventSeverity parseEventSeverity(const char *name) { return EventSeverity(-1); } -::std::ostream& operator<<(::std::ostream& os, EventSeverity eventSeverity) { +const char *stringifyEventSeverity(EventSeverity eventSeverity) { switch (eventSeverity) { - case EventSeverity::Debug: return os << "DEBUG"; - case EventSeverity::Info: return os << "INFO"; - case EventSeverity::Test: return os << "TEST"; - case EventSeverity::Warning: return os << "WARNING"; - case EventSeverity::Error: return os << "ERROR"; - default: return os << "UNKNOWN"; + case EventSeverity::Debug: return "DEBUG"; + case EventSeverity::Info: return "INFO"; + case EventSeverity::Test: return "TEST"; + case EventSeverity::Warning: return "WARNING"; + case EventSeverity::Error: return "ERROR"; + default: return "UNKNOWN"; } } +::std::ostream& operator<<(::std::ostream& os, EventSeverity eventSeverity) { + return os << stringifyEventSeverity(eventSeverity); +} + Event parseEvent(const char *name) { + if (strcmp(name, "Setup") == 0) return Event::Setup; if (strcmp(name, "ParseStyle") == 0) return Event::ParseStyle; if (strcmp(name, "ParseTile") == 0) return Event::ParseTile; if (strcmp(name, "Render") == 0) return Event::Render; @@ -32,15 +37,20 @@ Event parseEvent(const char *name) { return Event(-1); } -::std::ostream& operator<<(::std::ostream& os, Event event) { - switch (event) { - case Event::ParseStyle: return os << "ParseStyle"; - case Event::ParseTile: return os << "ParseTile"; - case Event::Render: return os << "Render"; - case Event::HttpRequest: return os << "HttpRequest"; - default: return os << "Unknown"; +const char *stringifyEvent(Event event) { + switch (event) { + case Event::Setup: return "Setup"; + case Event::ParseStyle: return "ParseStyle"; + case Event::ParseTile: return "ParseTile"; + case Event::Render: return "Render"; + case Event::HttpRequest: return "HttpRequest"; + default: return "Unknown"; } } +::std::ostream& operator<<(::std::ostream& os, Event event) { + return os << stringifyEvent(event); +} + }