emilk / loguru Goto Github PK
View Code? Open in Web Editor NEWA lightweight C++ logging library
License: The Unlicense
A lightweight C++ logging library
License: The Unlicense
When LOGURU_USE_FMTLIB is set to 1, loguru's internally-generated messages are incorrect.
Example:
date time ( uptime ) [ thread name/id ] file:line v|
2018-01-03 20:54:55.652 ( 0.000s) [main thread ] loguru.hpp:1828 0| arguments: %s
2018-01-03 20:54:55.653 ( 0.001s) [main thread ] loguru.hpp:1831 0| Current dir: %s
2018-01-03 20:54:55.653 ( 0.001s) [main thread ] loguru.hpp:1833 0| stderr verbosity: %d
2018-01-03 20:54:55.653 ( 0.001s) [main thread ] loguru.hpp:1834 0| -----------------------------------
2018-01-03 20:54:55.654 ( 0.001s) [main thread ] loguru.hpp:1986 0| Logging to '%s', mode: '%s', verbosity: %d
from the readme example, the LOG_SCOPE_FUNCTION_F does not exists.
Should it be LOG_SCOPE_FUNCTION instead?...
I'm using Windows with _UNICODE
defined and trying to output some %ls
with LOG_F()
. It went well until a string with non-ASCII characters appeared and then the program aborted with CHECK FAILED: bytes_needed >= 0 Bad string format: '%ls'
. It looks like the problem is caused by _vscprintf()
, which has a wchar variant but requires a format string with the same type (so I guess it can't be a replacement). I also tried LOG_S()
, but it output the address of the string instead of the content (it was using the ostream& operator<< (const void* val )
overload). Any ideas?
Example:
LOG_S(INFO) << L"哇r";
LOG_F(INFO, "%ls", L"哇r");
...:175 0| 00007FF6D607EA70
...:1668 FATL| CHECK FAILED: bytes_needed >= 0 Bad string format: '%ls'
Line 2329 in bead388
Ref: http://www.cplusplus.com/reference/cstdio/snprintf/
buf_size
is size_t
, but out_buff_size - pos
may produce negative value.out_buff_size == 0
, there is no \0
.I'd like to have a #define (or API call) to turn color on and off. Would help if I have to log to a file.
It's very helpful for management of submodules to have tags also for minor release. Currently, 1.5.1 is not tagged.
Hi, can you update your documentation related to usage:
#define LOGURU_IMPLEMENTATION 1
the 1 is missing in the readme, without 1 it will fail to build.
Loguru doesn't compile on Debian Jessie with g++ 4.9.2 because PATH_MAX
isn't defined. I have a basic fix here (it has a typo, MAX_PATH
instead of PATH_MAX
). It also doesn't compile with g++ 5.3 on Mac OS X, because that requires to include limits.h
to get PATH_MAX
.
I would propose the following solution:
limits.h
first.PATH_MAX
is not defined yet, and it is a Linux environment, include linux/limits.h
PATH_MAX
to a reasonable default, e.g. 1024.The most important point here I think is to have a default to fallback on, because apparently, PATH_MAX
is not reliable at all.
Thanks for the awesome library.
Would you be interested in adding line numbers to the stack trace on OSX (if debug symbols are present)? There's some code for doing this (using the atos
utility) here:
On Linux, addr2line
could be used.
This library seems interesting and well designed, but compilation is slow here.
Any idea of where the bottleneck is, and perhaps how it could be trimmed down to compile faster?
Fortunately, compilation time is reduced to ~0.4s when not #define LOGURU_IMPLEMENTATION 1
, so the problem should be solved by defining a dedicated compilation unit (cpp file) for that.
Ubuntu 18.04 running on a Intel(R) Core(TM) i7-4710HQ CPU @ 2.50GHz .
This is obviously not IO-bound (fast SSD, 16GB RAM, files in cache).
System is otherwise idle.
# Compilation options from the `loguru_example/CMakeLists.txt` :
time /usr/bin/c++ -std=c++11 -Werror -Wall -Wextra -pedantic -fsanitize=address -fno-omit-frame-pointer -O2 -g -DNDEBUG -o main.cpp.o -c main.cpp
# Various runs :
real 0m10,722s
user 0m10,533s
sys 0m0,170s
real 0m11,182s
user 0m11,048s
sys 0m0,132s
real 0m11,360s
user 0m11,176s
sys 0m0,180s
real 0m11,439s
user 0m11,222s
sys 0m0,217s
This is a very ugly example:
visualize(std::vector<Eigen::Matrix<float, 3, 1, 0, 3, 1>, Eigen::aligned_allocator<Eigen::Matrix<float, 3, 1, 0, 3, 1> > > const&)
The allocators could be removed by matching std::vector<Foo,Bar>
where Bar
has an equal number of <>. This would give us:
visualize(std::vector<Eigen::Matrix<float, 3, 1, 0, 3, 1> > const&)
To cleanup further we could let the Loguru user install hookups for replacing e.g. Eigen::Matrix<float, 3, 1, 0, 3, 1>
with Vector3f
, which would give us:
visualize(std::vector<Vector3f> const&)
../../third_party/loguru\loguru.hpp:1636:16: error: use of undeclared identifier 'vasprintf'; did you mean 'vsprintf'?
int result = vasprintf(&buff, format, vlist);
^
D:\msys64\mingw64\x86_64-w64-mingw32\include\stdio.h:372:5: note: 'vsprintf' declared here
int vsprintf (char *__stream, const char *__format, __builtin_va_list __local_argv)
^
In file included from ../../src/third_party_impl.cc:5:
../../third_party/loguru\loguru.hpp:1636:26: error: cannot initialize a parameter of type 'char *' with an rvalue of type 'char **'
int result = vasprintf(&buff, format, vlist);
^~~~~
D:\msys64\mingw64\x86_64-w64-mingw32\include\stdio.h:372:21: note: passing argument to parameter '__stream' here
int vsprintf (char *__stream, const char *__format, __builtin_va_list __local_argv)
^
In file included from ../../src/third_party_impl.cc:5:
../../third_party/loguru\loguru.hpp:1878:3: error: use of undeclared identifier 'localtime_r'; did you mean 'localtime_s'?
localtime_r(&sec_since_epoch, &time_info);
^
D:\msys64\mingw64\x86_64-w64-mingw32\include\time.h:261:31: note: 'localtime_s' declared here
__forceinline errno_t __cdecl localtime_s(struct tm *_Tm,const time_t *_Time) { return _localtime64_s(_Tm,_Time); }
^
In file included from ../../src/third_party_impl.cc:5:
../../third_party/loguru\loguru.hpp:1878:15: error: cannot initialize a parameter of type 'struct tm *' with an rvalue of type 'time_t *' (aka 'long long *')
localtime_r(&sec_since_epoch, &time_info);
^~~~~~~~~~~~~~~~
D:\msys64\mingw64\x86_64-w64-mingw32\include\time.h:261:54: note: passing argument to parameter '_Tm' here
__forceinline errno_t __cdecl localtime_s(struct tm *_Tm,const time_t *_Time) { return _localtime64_s(_Tm,_Time); }
^
In file included from ../../src/third_party_impl.cc:5:
../../third_party/loguru\loguru.hpp:1946:8: error: no matching function for call to 'mkdir'
if (mkdir(file_path, 0755) == -1) {
^~~~~
D:\msys64\mingw64\x86_64-w64-mingw32\include\io.h:280:15: note: candidate function not viable: requires 1 argument, but 2 were provided
int __cdecl mkdir (const char *) __MINGW_ATTRIB_DEPRECATED_MSVC2005;
^
In file included from ../../src/third_party_impl.cc:5:
../../third_party/loguru\loguru.hpp:2311:3: error: use of undeclared identifier 'localtime_r'; did you mean 'localtime_s'?
localtime_r(&sec_since_epoch, &time_info);
^
D:\msys64\mingw64\x86_64-w64-mingw32\include\time.h:261:31: note: 'localtime_s' declared here
__forceinline errno_t __cdecl localtime_s(struct tm *_Tm,const time_t *_Time) { return _localtime64_s(_Tm,_Time); }
^
In file included from ../../src/third_party_impl.cc:5:
../../third_party/loguru\loguru.hpp:2311:15: error: cannot initialize a parameter of type 'struct tm *' with an rvalue of type 'time_t *' (aka 'long long *')
localtime_r(&sec_since_epoch, &time_info);
^~~~~~~~~~~~~~~~
D:\msys64\mingw64\x86_64-w64-mingw32\include\time.h:261:54: note: passing argument to parameter '_Tm' here
__forceinline errno_t __cdecl localtime_s(struct tm *_Tm,const time_t *_Time) { return _localtime64_s(_Tm,_Time); }
^
In file included from ../../src/third_party_impl.cc:5:
../../third_party/loguru\loguru.hpp:2805:4: error: "No signal handlers on Win32" [-Werror,-W#warnings]
#warning "No signal handlers on Win32"
^
8 errors generated.
[27/71] Compiling src/clang_translation_unit.cc
Waf: Leaving directory `/d/shaman/cquery/build/release'
Build failed
-> task in 'bin/cquery' failed with exit status 1 (run with -v to display more information)
On Linux, the default thread name is the same as the name of the binary. Additionally, any new threads seem to inherit the name of the thread it got forked from. This means in the current form, all threads get the same name in the log by default.
Finding a solution for this is far from trivial. Loguru could have its own thread_id->name map, but that would be invalid if thread_id are reused. Another approach is to use thread_local storage, but compiler support for that is not very good at the moment.
add_file() with just these two params is not defined. It requires the 3rd verbosity param.
// Put every log message in "everything.log":
loguru::add_file("everything.log", loguru::Append);
Here, loguru::INFO
doesn't work but loguru::Verbosity_INFO
does.
// Only log INFO, WARNING, ERROR and FATAL to "latest_readable.log":
loguru::add_file("latest_readable.log", loguru::Truncate, loguru::INFO);
Thanks for the library!
Hi
I have this error in Ubuntu, using logger in so library, loading library from Mono.
Have no ideas why.
I am currently adding loguru to an application that already uses -v
for another parameter. It would be very useful to be able to specify a custom parameter name for the verbosity level to loguru. Alternatively, It would be great to get all the features of init
without parsing command-line arguments.
Tested using segfaults, uncaught exceptions, and abort
, none of the ErrorContext
entries were printed on MSVC2015 x64.
When trying to compile cquery on Void Linux with musl libc I get the following error.
loguru.hpp:1391:11: fatal error: execinfo.h: No such file or directory
#include <execinfo.h> // for backtrace
execinfo.h
is glibc
specific and prevents compilation when using alternative standard libraries.
Is it possible to restructure loguru so that support doesn't depend on glibc
?
loguru.hpp:2218:30: error: cannot use
typeid with -fno-rtti
Any plans to add rsyslog so that logs are viewable in say Papertrail? It's just sending UDP packets.
.
ArgList does not exist any more in recent versions of fmtlib leading to the obvious compiler error
'fmt::ArgList' has not been declared
when LOGURU_USE_FMTLIB is enabled.
It would be nice to have abort as optional behavior for FATAL log level without throwing exception.
Hello,
I would like to report an issue with the library. If the length of a filename is bigger than 23 characters the snprintf corrupts the stack. Here is one of the lines affected by this issue:
https://github.com/emilk/loguru/blob/master/loguru.hpp#L2429
The same concepts affects the thread name.
Thanks for the great work!
Hi, it would be good if loguru supports keep constant log file size,
but update log in the file, like spdlog's rotate logger:
// Create a file rotating logger with 5mb size max and 3 rotated files
auto rotating_logger = spd::rotating_logger_mt("some_logger_name", "logs/mylogfile", 1048576 * 5, 3);
for (int i = 0; i < 10; ++i)
rotating_logger->info("{} * {} equals {:>10}", i, i, i*i);
Hi, how to work around this error?
loguru.h(452): error C2610: 'loguru::LogScopeRAII::LogScopeRAII(loguru::LogScopeRAII &&)' : is not a special member function which can be defaulted
// Helper class for LOG_SCOPE_F
class LogScopeRAII
{
public:
LogScopeRAII() : _file(nullptr) {} // No logging
LogScopeRAII(Verbosity verbosity, const char* file, unsigned line, LOGURU_FORMAT_STRING_TYPE format, ...) LOGURU_PRINTF_LIKE(5, 6);
~LogScopeRAII();
LogScopeRAII(LogScopeRAII&& other) = default; // here
I tested the demo program on Windows.
It cannot be compiled on this system.
On line 780 of loguru.hpp I have this following error:
fatal error: dlfcn.h: No such file or directory
This kind of error also occurred with pthread.h.
I used MinGW (g++ 4.7.1) on Windows 7. It does not provide these files. But is seems that Cygwin provides them (not tested).
Is there a way to make this library usable on windows with these compilers (g++, Visual C++, ...) without getting any dependencies?
I get the following errors trying to compile on Windows using MinGW version: w64 5.0
loguru.hpp: In function 'loguru::Text loguru::vtextprintf(const char*, va_list)': loguru.hpp:1603:46: error: 'vasprintf' was not declared in this scope int result = vasprintf(&buff, format, vlist);
And
loguru.hpp: In function 'bool loguru::create_directories(const char*)': loguru.hpp:1907:29: error: too many arguments to function 'int mkdir(const char*)' if (mkdir(file_path, 0755) == -1)
Any suggestions?
It is weird that the indentation is based on the highest verbosity level (current_verbosity_cutoff
) rather than stderr
when reading stderr
. But it is also weird to have it based on g_stderr_verbosity
when reading the log files.
The cleanest solution is to have different indentation per output.
It is possible to different threads write on different log files?
Experienced on a Tegra TK1 running Ubuntu 14.04 32-bit with GCC 4.8 compiler.
With -O2 optimizations turned on, we see a shift in bytes for the arguments passed on to snprintf() called in get_thread_name().
void get_thread_name(char* buffer, unsigned long long length, bool right_align_hext_id)
{
...
if (right_align_hext_id) {
snprintf(buffer, length, "%*X", length - 1, static_cast<unsigned>(thread_id));
} else {
snprintf(buffer, length, "%X", static_cast<unsigned>(thread_id));
}
}
The parameter unsigned long long length
passed into the function is used in the snprintf() function; The *
in the %*X
is expecting a type int. This style of va_args may under some conditions be misinterpreted (only the first half of the long long is taken, shoving the rest of the long long into the coming parameter). While later versions of GCC may be smarter about it, it may not always work with all compilers.
Suggested solution: prepare the type cast before the snprintf call. Example:
void get_thread_name(char* buffer, unsigned long long long_length, bool right_align_hext_id)
{
int length = static_cast<int>(long_length);
Additional details:
(1) Valgrind reports "Conditional jump or move depends on uninitialised value(s)" around the loguru::get_thread_name
(2) Breakpointing and tracing the calls with GDB revealed this (emphasis added):
Breakpoint 2, __GI__IO_padn (fp=fp@entry=0xbeffef38, pad=pad@entry=48, count=1) at iopadn.c:47
Breakpoint 2, __GI__IO_padn (fp=fp@entry=0xbeffef38, pad=32, count=count@entry=1) at iopadn.c:47
Breakpoint 2, __GI__IO_padn (fp=fp@entry=0xbeffef38, pad=pad@entry=32, count=count@entry=14) at iopadn.c:47
Breakpoint 2, __GI__IO_padn (fp=fp@entry=0xbeffef38, pad=pad@entry=32, count=count@entry=3) at iopadn.c:47
// ^ a series of consecutive calls to a glibc function called
_IO_padn
.
// And then comes this, after the call toget_thread_name
:
Breakpoint 2, __GI__IO_padn (fp=fp@entry=0xbeffeef0, pad=pad@entry=32, count=count@entry=1090522931) at iopadn.c:47
Full backtrace:
(gdb) bt
#0 _IO_strn_overflow (fp=0xbeffeef0, c=32) at vsnprintf.c:66
#1 0xb6dfa1ee in __GI__IO_default_xsputn (f=0xbeffeef0, data=<optimized out>, n=16) at genops.c:480
#2 0xb6df238c in __GI__IO_padn (fp=fp@entry=0xbeffeef0, pad=pad@entry=32, count=count@entry=1090522931) at iopadn.c:59
#3 0xb6dddae6 in _IO_vfprintf_internal (s=s@entry=0xbeffeef0, format=format@entry=0x13994 "%*X", ap=..., ap@entry=...) at vfprintf.c:1660
#4 0xb6e47a9e in ___vsnprintf_chk (s=s@entry=0xbefff100 "A ", maxlen=<optimized out>, maxlen@entry=11, flags=flags@entry=1, slen=slen@entry=4294967295, format=format@entry=0x13994 "%*X", args=...) at vsnprintf_chk.c:63
#5 0xb6e47a40 in ___snprintf_chk (s=s@entry=0xbefff100 "A ", maxlen=maxlen@entry=11, flags=flags@entry=1, slen=slen@entry=4294967295, format=format@entry=0x13994 "%*X") at snprintf_chk.c:34
#6 0x0000d9a0 in snprintf (__fmt=0x13994 "%*X", __n=11, __s=0xbefff100 "A ") at /usr/include/arm-linux-gnueabihf/bits/stdio2.h:65
#7 loguru::get_thread_name (buffer=buffer@entry=0xbefff100 "A ", length=<optimized out>, right_align_hext_id=right_align_hext_id@entry=true) at loguru.hpp:1957
#8 0x0000db22 in loguru::print_preamble (out_buff=out_buff@entry=0xbefff15c "", verbosity=verbosity@entry=-2, file=file@entry=0x13b78 "main.cpp", line=line@entry=9, out_buff_size=128) at loguru.hpp:2113
#9 0x0000d24c in loguru::log_to_everywhere (stack_trace_skip=stack_trace_skip@entry=1, verbosity=verbosity@entry=-2, file=file@entry=0x13b78 "main.cpp", line=line@entry=9, prefix=prefix@entry=0x1378c "", buff=buff@entry=0x244c0 "Something has ceased to work.\n") at loguru.hpp:2257
#10 0x0000dfe6 in loguru::log (verbosity=-2, file=0x13b78 "main.cpp", line=9, format=0x137bc "%s") at loguru.hpp:2267
#11 0x0000e5aa in loguru::StreamLogger::~StreamLogger (this=0xbefff268, __in_chrg=<optimized out>) at loguru.hpp:2381
#12 0x0000ad12 in main () at main.cpp:9
And the address reveal of the va_list argument passed shows that there is a byte alignment issue:
(gdb) x/100dw 0xbeffef60
0xbeffef60: -1225102064 -1225102868 -1090523232 0
0xbeffef70: 2111285930 -1224842949 -1224761344 -1225100160
0xbeffef80: -1225102064 -1224741480 -1226257992 -1090523088
0xbeffef90: 0 -1224738620 -1224790084 -1224741480
0xbeffefa0: 0 0 1 119
0xbeffefb0: -1224756240 -1224753152 36981 -1225096944
0xbeffefc0: 35596 1 -1224756336 -1224738024
0xbeffefd0: -1224738464 36981 -1090523120 -1090523108
0xbeffefe0: 80276 -1090522880 1 -1224761344
0xbeffeff0: 11 -1226540479 80276 -1090523108
0xbefff000: -1090522880 -1090523108 -1224761344 10
0xbefff010: 0 55713 80276 -1090522932
0xbefff020: 10 0 -1224761344 802944595
First, thanks for this awesome logging library. This is exactly what I needed. Although it required some manual patching to get the deprecation warnings and ISO C stuff sorted out. (http://pastebin.com/gRSSeuvv), since this is not about the deprecation warnings I left them out and just pastebinned them.
The real "issue" is this error:
error C2398: Element '3': conversion from 'long' to 'unsigned int' requires a narrowing conversion
which originates from here:
#define VLOG_SCOPE_F(verbosity, ...) \
loguru::LogScopeRAII LOGURU_ANONYMOUS_VARIABLE(error_context_RAII_) = \
((verbosity) > loguru::current_verbosity_cutoff()) ? loguru::LogScopeRAII() : \
loguru::LogScopeRAII{verbosity, __FILE__, __LINE__, __VA_ARGS__}
Adding a C Style cast to __LINE__
fixes the problem though.
#define VLOG_SCOPE_F(verbosity, ...) \
loguru::LogScopeRAII LOGURU_ANONYMOUS_VARIABLE(error_context_RAII_) = \
((verbosity) > loguru::current_verbosity_cutoff()) ? loguru::LogScopeRAII() : \
loguru::LogScopeRAII{verbosity, __FILE__, (unsigned int)__LINE__, __VA_ARGS__}
I'm using the stream versions of Loguru macros but I can't find a stream version for:
LOG_SCOPE_F(INFO, "some message");
Am I missing something ?
Sometimes I emit messages from files with long names, and then the log won't be properly aligned anymore. This will look something like this:
2016-09-29 11:51:16.879 ( 2.985s) [main thread ]really_long_source_file_name.cpp:144 0| Some message that is not properly aligned
2016-09-29 11:51:16.879 ( 2.985s) [main thread ] short.hpp:202 0| Some other message.
Since this is a static property of the project, it would be nice to have a macro to define to control the padding. If you can point me to the relevant part of the source code, I can also have a look at it.
It will be awesome if the 1900 + time_info.tm_year
column can be hidden (via a customization option)
void write_date_time(char* buff, size_t buff_size)
{
auto now = system_clock::now();
long long ms_since_epoch = duration_cast<milliseconds>(now.time_since_epoch()).count();
time_t sec_since_epoch = time_t(ms_since_epoch / 1000);
tm time_info;
localtime_r(&sec_since_epoch, &time_info);
snprintf(buff, buff_size, "%04d%02d%02d_%02d%02d%02d.%03lld",
1900 + time_info.tm_year, 1 + time_info.tm_mon, time_info.tm_mday,
time_info.tm_hour, time_info.tm_min, time_info.tm_sec, ms_since_epoch % 1000);
}
loguru has been working great for me (👍). I'm wondering if you plan to support custom output layout. E.g. Sometimes thread names are not needed.
The ERROR_CONTEXT information is stored per thread and is not copied to new threads. This makes it harder to debug code with parallelization. I would like to be able to copy/access the error context from the parent thread to/in new threads to make debugging easier.
Hi, how to use loguru callback function?
i am trying to send error message to another thread.
to use it, i tried to use event queue from mbed-events library.
it seems work fine.
https://github.com/ARMmbed/mbed-events
My system: Ubuntu 18.04.1 LTS.
I would like to easily distinguish errors and warnings in the log lines on the terminal. However, ERR and WRN lines now have identical colors.
In loguru, color code 31 is used for warnings and 91 for errors (and fatal). These are the intended colors:
The colors are distinguishable (although quite similar).
However, the ERR and WRN log lines in loguru not only have a color, they are also printed bold. This is how text is written on my terminal in bold:
As you can see, the colors now are identical.
My suggestion to solve this problem would be to use a different color for WRN log entries. For me a perfect joice would be terminal_yellow() (color code 33) since this would be derived from the traffic light system and, thus, would be completely intuitive for me.
This is to bring Loguru in line with GLOG
Hey,
I am using your logging system for my custom game engine, great work on the library btw.
But I am running into an issue when I create a dynamic version of my engine library because your log functions are not exported, would it be possible to create some definition to export the function declerations so they can be used outside the library?
loguru::init() leaks a small amount of memory (12 bytes) in every single execution. This can be verified by running
$ valgrind --leak-check=full --show-leak-kinds=all program
I'll see if i can find the problem and push a fix!
Hi, i want that loguru support unicode.
#define LOG_INFO(...) LOG_F(INFO, __VA_ARGS__)
void function(const std::wstring& fn)
{
LOG_INFO(" %s file opened\n", fn); // not work
LOG_INFO(" %s file opened\n", fn.c_str()); // not work
std::string str(fn.begin(), fn.end());
LOG_INFO(" %s file opened\n", str.c_str()); // work
}
.../code/project/include/log/loguru.hpp:1168:69: error: use of non-standard escape character '\e' [-Werror,-Wpedantic]
const char* terminal_black() { return s_terminal_has_color ? "\e[30m" : ""; }
I can't compile with loguru because I get a bazillion errors like these in pedantic mode in clang!
What do I do!?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.