draios / sysdig Goto Github PK
View Code? Open in Web Editor NEWLinux system exploration and troubleshooting tool with first class support for containers
Home Page: http://www.sysdig.com/
License: Other
Linux system exploration and troubleshooting tool with first class support for containers
Home Page: http://www.sysdig.com/
License: Other
Installation on OSX should be easier than manual compilation, and Homebrew seems to be the best alternative these days.
Right now if we do
sysdig evt.buffer contains 'www.google.com'
We get just the specific events that contain the specified token.
It would be nice if this was stateful per-fd (maybe with a different filtering field?), like it already happens for paths, connections, etc., so that sysdig could be used in a "follow conversation"-like mode.
My build is failing with this file on Arch Linux running GCC 4.8.2 on x86_64. I've include a build log with some system information at the bottom. I've checked and if i remove all of the fprint then the build works fine. Let me know what else I can include.
the clone and execve filler only captures the process executable name, not the full exe. This creates inconsistencies with getting the info from proc.
HOW TO REPLICATE
# sysdig -p "%user.id %user.name" evt.type=open
0 root
498216206444 snmp
498216206444 snmp
498216206444 snmp
498216206444 snmp
^C
# id snmp
uid=108(snmp) gid=116(snmp) groups=116(snmp)
# uname -a
Linux bgregg-test-i-27eff009 3.2.0-54-virtual #82-Ubuntu SMP Tue Sep 10 20:31:18 UTC 2013 x86_64 x86_64 x86_64 GNU/Linux
# sysdig -h
sysdig version 0.1.72
[...]
That should show UID 108 and not 498216206444.
A stack field class could be included, with stack.kernel and stack.user for retrieving each stack back trace. This would allow quick identification of the reason events occurred: code path ancestry.
A minor detail: it doesn't matter if stacks are returned multi-line (easier to read) or single-line (easier to post process). Eg, for single line, frames can be separated by ';'.
(Stack trace data can also be easily fed into Flame Graphs...)
Very useful when troubleshooting socket issues
There are a bunch of free hosted CI services that would be useful for sysdig.
We won't be able to build/test the driver, but for that we have our own (private for the moment) CI server.
The main advantage is that we could spin a build automatically for every pull request, and build it on Linux/OSX/Windows (so it's kind of important that the chosen service supports all these).
Implement json output for easier integrations with third-party components (will be useful for Draios as well)
binary buffers are currently rendered in a very simple way: unprintable characters are replaced with a '.'.
There should be an option to to display them as hex/ascii, like the -x and -X option in tcpdump
it should be possible to wrap a filter arument in quotes in case it includes spaces or other non-stanrdar characters.
For example, the following filter
evt.arg.data contains "foo bar"
is not supported today
Just a very utopical idea, but we got a few people who can't use sysdig on some public cloud providers (e.g. Linode) because they don't have easy access to the kernel headers.
It would be nice (and pretty innovative, I've never seen something around like this) to prebuild all those modules and put them on a HTTPS web server so the right one can be downloaded on the fly during the installation, and fallback to the dkms stuff if it doesn't work.
The similar attempts I've seen (e.g. VMWare tools) didn't work well at all, first because the number of kernel versions supported is too little, and second because precompiled binaries are shipped in a big tarball which is a pain.
The flags and/or commands for several system calls (clone, open, fcntl, poll, lssek, futex...) are already captured by the driver and converted to system-independent enumerations.
Sysdig/linsinsp, however, don't print these values in the output; they just print the raw number. They also don't let these flags to be specified in filters.
The hard part here is deciding how to implement this: the cleanest way to implement this involves creating a different datatype for any of these flags, but that would bring to a proliferation of datatypes that could decrease efficiency and the cleanliness of the datatype system.
I wrote a basic opensnoop in sysdig. Only captures successful opens (modulus #47). Before sharing this as an example, I thought I'd add it here as you might have ideas for improving it first. Eg, include field widths in sysdig's output formatting? Or should this kind of formatting always be left for post-processing (eg, awk/shell)?
# sysdig -p "%user.name %proc.pid %proc.name %fd.num %fd.typechar %fd.name" evt.type=open | awk '
BEGIN { printf " %-12s %-6s %-12s %3s %s %s\n", "USER", "PID", "COMM", "FD", "S", "TARGET" }
{ printf " %-12s %-6s %-12s %3s %s %s\n", $1, $2, $3, $4, $5, $6 }'
USER PID COMM FD S TARGET
root 8084 sysdig 0 f /dev/pts/0
snmp 29128 snmp-pass 3 f /proc/cpuinfo
snmp 23430 snmp-pass 3 f /proc/cpuinfo
snmp 29128 snmp-pass 3 f /proc/stat
snmp 23430 snmp-pass 3 f /proc/stat
snmp 23430 snmp-pass 3 f /proc/cpuinfo
snmp 29128 snmp-pass 3 f /proc/cpuinfo
snmp 23430 snmp-pass 3 f /proc/stat
root 8245 sshd 10 f /proc/self/oom_score_adj
root 8245 sshd 3 f /etc/ld.so.cache
root 8245 sshd 3 f /lib/x86_64-linux-gnu/libwrap.so.0
root 8245 sshd 3 f /lib/x86_64-linux-gnu/libpam.so.0
root 8245 sshd 3 f /lib/x86_64-linux-gnu/libselinux.so.1
Hi,
while sysdig seems to build fine with cmake, the "make package" rule doesn't work (at least not for building debs) on fresh git checkout, as SYSDIG_VERSION isn't defined, which leaves the various version-fields CPpack depends on undefined.
Not sure what'd be the recommended way of maintaining a proper SYSDIG_VERISION, but in the mean time it should at least be listed somewhere that SYSDIG_VERSION needs to be defined in order to build packages. This needs to be defined for cmake, eg:
mkdir build
cd build
cmake -D SYSDIG_VERSION=0.1
make package # fails without SYSDIG_VERSION above
It has been asked by a couple folks.
It should be possible to let the user use their own version of LuaJIT.
This basically requires adding a parameter to cmake like "WITH_SYSTEM_LUAJIT=ON" or something, and then just link dynamically instead of statically.
Very straightforward.
Changes in the machine network interfaces should be detected (for example by polling the interface list every 30 seconds) and the list should be updated in the libsinsp state.
Also, a new interface list block should be added to the dump file if dump to disk is enabled. This means that the dump file read code should handle interface blocks in the middle of event blocks.
When I try to run a 2nd sysdig while one is still running:
# sysdig "proc.name=httpd"
error opening device /dev/sysdig0. Make sure you have root credentials and that the sysdig-probe module is loaded.
The sysdig User Guide didn't mention that only one user at a time could use sysdig. This could be a problem if people want to setup some 24x7 logging, but still use more sysdig interactively. But that might not be the real intent of sysdig.
Fedora seems to be installed by default with the PAE kernel on some cloud providers, so it would be good if the installer detected that instead of just printing a warning.
A lot of people are having problems by running a cmake in-tree build, which causes a loop while compiling the kernel module.
It should be easy to detect the condition and print an user-friendly message that points to the wiki and suggests out-of-tree build.
I tried building (from a git clone) on opensuse 12.3 however the build failed when trying to build the driver (despite no error from cmake).
It appears that 'build' was appended to the path used:
canning dependencies of target driver
make: *** /lib/modules/3.7.10-1.1-desktop/build: No such file or directory. Stop.
make[3]: *** [all] Error 2
make[2]: *** [driver/CMakeFiles/driver] Error 2
make[1]: *** [driver/CMakeFiles/driver.dir/all] Error 2
make: *** [all] Error 2
The correct path looks to be /lib/modules/3.7.10-1.1-desktop. I also attempted to do an inplace build (using cmake .) however this appeared to enter a loop finding the dependencies and forced me to reboot.
sysdig seems quite excellent, the problem I see is that since I work on a plethora of platforms one of the more commonly used (sadly) is still EL5.
As such, I'd love to see sysdig available for EL5, is this possible?
From https://github.com/draios/sysdig/wiki/Sysdig%20User%20Guide#output-formatting:
Here’s an example:
$ sysdig -p"user:%user.name dir:%evt.arg.path" evt.type=chdir
ubuntu /root
ubuntu /root/tmp
ubuntu /root/Download
The output does not match the command. The output should be:
user:ubuntu dir:/root
user:ubuntu dir:/root/tmp
user:ubuntu dir:/root/Download
It's pretty noticeable since it's the first example given of output formatting. :-)
We have a nice test framework, with unit tests that stress pretty much every system call intercepted by sysdig, as well as other features.
We've not published them yet because they need some polishing and they rely on some big third-party libraries that we don't want users to necessarily download/compile.
All this to say: don't start working on a new testing framework for sysdig, it's coming soon!
very often, when saving to file it's useful to increase the portion of the network buffers, but not of the disk buffers.
It would be nice to have the granularity to choose how much to save for different types of FDs.
# sysdig -p "%fd.num %fd.name" "evt.type=open and proc.name=df and evt.rawarg.fd<0"
Segmentation fault (core dumped)
# gdb `which sysdig` core.sysdig.13591.bgregg-test
[...]
Core was generated by `sysdig -p %fd.num %fd.name evt.type=open and proc.name=df and evt.rawarg.fd<0'.
Program terminated with signal 11, Segmentation fault.
#0 0x0000000000438144 in sinsp_filter_check::string_to_rawval(char const*, ppm_param_type) ()
(gdb) bt
#0 0x0000000000438144 in sinsp_filter_check::string_to_rawval(char const*, ppm_param_type) ()
#1 0x000000000043aaa5 in sinsp_filter_check_event::parse_filter_value(char const*) ()
#2 0x0000000000438c42 in sinsp_filter::parse_check(sinsp_filter_expression*, boolop) ()
#3 0x0000000000439a23 in sinsp_filter::compile(std::string) ()
#4 0x000000000043a1ca in sinsp_filter::sinsp_filter(sinsp*, std::string) ()
#5 0x0000000000451358 in sinsp::set_filter(std::string) ()
#6 0x000000000041bc11 in main ()
# uname -a
Linux bgregg-test-i-27eff009 3.2.0-54-virtual #82-Ubuntu SMP Tue Sep 10 20:31:18 UTC 2013 x86_64 x86_64 x86_64 GNU/Linux
# sysdig -h
sysdig version 0.1.72
If the same chisel is added twice (e.g. both in /usr/share/sysdig/chisels and ~/.chisels), then it will be counted twice in the list, and it's impossible to recognize which one gets executed when selected.
from the installer script:
curl -s http://download.draios.com/DRAIOS-GPG-KEY.public | apt-key add -
This is bad because there's no authentication; anyone could MITM this. HTTPS would solve this problem.
There should be a sysdig option to convert IP addresses into host names doing reverse dns lookup. It should be done using an async DNS library like c-ares to speed up the resolution.
I am getting error during compiling.
System info:
Arch linux x86_64
Kernel: 3.12.7-2
Cmake: 2.8.12.1
Make: 4.0
LuaJIT: 2.0.3
LuaJIT 2.0.3 installed on the system but sysdig trying to install LuaJIT 2.0.2.
Error message:
$ cd build
$ cmake ..
$ make
Scanning dependencies of target luajit
[ 2%] Creating directories for 'luajit'
[ 5%] No download step for 'luajit'
[ 7%] No patch step for 'luajit'
[ 10%] No update step for 'luajit'
[ 13%] No configure step for 'luajit'
[ 15%] Performing build step for 'luajit'
==== Building LuaJIT 2.0.2 ====
==== Successfully built LuaJIT 2.0.2 ====
[ 18%] No install step for 'luajit'
[ 21%] Completed 'luajit'
[ 21%] Built target luajit
Scanning dependencies of target driver
make[4]: *** /lib/modules/3.12.7-2-ARCH/build: No such file or directory. Stop.
Makefile:9: recipe for target 'all' failed
make[3]: *** [all] Error 2
driver/CMakeFiles/driver.dir/build.make:52: recipe for target 'driver/CMakeFiles/driver' failed
make[2]: *** [driver/CMakeFiles/driver] Error 2
CMakeFiles/Makefile2:113: recipe for target 'driver/CMakeFiles/driver.dir/all' failed
make[1]: *** [driver/CMakeFiles/driver.dir/all] Error 2
Makefile:136: recipe for target 'all' failed
make: *** [all] Error 2
This should be not best place for asking. Sorry if it so.
Thanks for helps.
This is debatable, mainly because we use dkms to manage sysdig-probe so there's no need to manually install the kernel driver, but we should allow a way to install it anyway in the current running kernel modules' directory.
Right now, make install just installs sysdig and chisels.
diff --git a/driver/ppm_fillers.c b/driver/ppm_fillers.c
index 8717786..2220032 100644
--- a/driver/ppm_fillers.c
+++ b/driver/ppm_fillers.c
@@ -3085,12 +3085,14 @@ static inline u8 fcntl_cmd_to_scap(unsigned long cmd)
return PPM_FCNTL_F_SETSIG;
case F_GETSIG:
return PPM_FCNTL_F_GETSIG;
+#ifndef CONFIG_64BIT
case F_GETLK64:
return PPM_FCNTL_F_GETLK64;
case F_SETLK64:
return PPM_FCNTL_F_SETLK64;
case F_SETLKW64:
return PPM_FCNTL_F_SETLKW64;
+#endif
case F_SETOWN_EX:
return PPM_FCNTL_F_SETOWN_EX;
case F_GETOWN_EX:
This is not hard per se, but requires including gzip as a dependency, which will make the build system much more complicated.
By default, sysdig writes entries to the log of itself writing entries to the log. Would be nice to filter out sysdig by default (with an option to enable for debug purposes?), filtered in the kernel (user-level for now).
# sysdig -w /tmp/out
# sysdig -r /tmp/out "proc.name=sysdig and evt.type=write" |more
25883 21:28:38.182317039 1 sysdig (14257) > write fd=5(<f>/tmp/out) size=4096
25884 21:28:38.182344198 1 sysdig (14257) < write res=4096 data=........M<+..............................`..............bgregg-test-i-2
7eff009..
25889 21:28:38.182369428 1 sysdig (14257) > write fd=5(<f>/tmp/out) size=4096
25890 21:28:38.182383233 1 sysdig (14257) < write res=4096 data=.........................rsyslogd../usr/sbin/rsyslogd..-c5.../.........
..e...g.
25891 21:28:38.182410715 1 sysdig (14257) > write fd=5(<f>/tmp/out) size=4096
25892 21:28:38.182423846 1 sysdig (14257) < write res=4096 data=pid.-g.-u.106:112.../............j...p...0.......0.......|.........plat
formservi
[...]
There's no reason why sysdig (the userspace part) should not build on Solaris, it's probably just a matter of putting some IFDEFs around libscap, it just hasn't been done yet.
If strace
shows the following:
9333 execve("/bin/i-dont-exist", ["/bin/i-dont-exist"], [/* 37 vars */]) = -1 ENOENT (No such file or directory)
...then I get the following for that same call from sysdig:
33504 15:07:27.665180219 0 <NA> (9333) > execve
33505 15:07:27.665205672 0 <NA> (9333) < execve res=-2(ENOENT) exe= args= tid=9333(<NA>) pid=9333(<NA>) ptid=9319(strace) cwd=/home/cduffy/VC/config-server fdlimit=4096
33506 15:07:27.665287065 0 <NA> (9333) > switch next=9319(strace)
Note the exe=
, showing an empty string passed for the destination path, whereas strace
shows the actual argument given.
We got a request to port sysdig to arm so it can be used on a raspberry pi, so I'm opening the issue and sharing the response:
We haven't had time to look into an ARM porting, so we don't have a clear idea of how long it would take (it depends on how different the system call interface is, and if some little tricks that we do inside the kernel driver would work on arm as well), but the answer is that it's definitely possible. Wisest thing to do is open a github issue and see if there's more interest to justify spending our time on such feature, or be lucky enough to have someone from the community contributing to it :)
I'm not allowed to add examples to the wiki, so i thought i'd share this.
Monitor all traffic between apache and mysql and dump the SELECT queries it executes
sysdig -A -c echo_fds fd.sip=192.168.30.5 and proc.name=apache2 | grep SELECT
port numbers should be converted into strings when rendered to screen using a public list so that 80 becomes http.
It should also be possible to specify resolved port names in filters, e.g.
fd.sport=http
Here's some unformatted output, showing a trace of open()s from "df -h":
# sysdig "evt.type=open and proc.name=df"
82176 20:25:03.791929880 0 df (13093) > open
82177 20:25:03.791934928 0 df (13093) < open fd=3(<f>/etc/ld.so.cache) name=/etc/ld.so.cache flags=1(O_RDONLY) mode=0
82186 20:25:03.791969141 0 df (13093) > open
82187 20:25:03.791973875 0 df (13093) < open fd=3(<f>/lib/x86_64-linux-gnu/libc.so.6) name=/lib/x86_64-linux-gnu/libc.so.6 flags=1(O_RDONLY) mode=0
82222 20:25:03.792457748 0 df (13093) > open
82223 20:25:03.792465897 0 df (13093) < open fd=3(<f>/usr/lib/locale/locale-archive) name=/usr/lib/locale/locale-archive flags=1(O_RDONLY) mode=0
82230 20:25:03.792550784 0 df (13093) > open
82231 20:25:03.792558080 0 df (13093) < open fd=3(<f>/etc/mtab) name=/etc/mtab flags=1(O_RDONLY) mode=0
82246 20:25:03.792706015 0 df (13093) > open
82247 20:25:03.792713387 0 df (13093) < open fd=3(<f>/usr/share/locale/locale.alias) name=/usr/share/locale/locale.alias flags=1(O_RDONLY) mode=0
82260 20:25:03.792793355 0 df (13093) > open
82261 20:25:03.792797051 0 df (13093) < open fd=-2(ENOENT) name=/usr/share/locale/en_US.UTF-8/LC_MESSAGES/coreutils.mo flags=1(O_RDONLY) mode=0
82262 20:25:03.792798626 0 df (13093) > open
82263 20:25:03.792800633 0 df (13093) < open fd=-2(ENOENT) name=/usr/share/locale/en_US.utf8/LC_MESSAGES/coreutils.mo flags=1(O_RDONLY) mode=0
82264 20:25:03.792801803 0 df (13093) > open
82265 20:25:03.792803901 0 df (13093) < open fd=-2(ENOENT) name=/usr/share/locale/en_US/LC_MESSAGES/coreutils.mo flags=1(O_RDONLY) mode=0
82266 20:25:03.792805075 0 df (13093) > open
82267 20:25:03.792807030 0 df (13093) < open fd=-2(ENOENT) name=/usr/share/locale/en.UTF-8/LC_MESSAGES/coreutils.mo flags=1(O_RDONLY) mode=0
82268 20:25:03.792808196 0 df (13093) > open
82269 20:25:03.792810387 0 df (13093) < open fd=-2(ENOENT) name=/usr/share/locale/en.utf8/LC_MESSAGES/coreutils.mo flags=1(O_RDONLY) mode=0
82270 20:25:03.792811521 0 df (13093) > open
82271 20:25:03.792814595 0 df (13093) < open fd=-2(ENOENT) name=/usr/share/locale/en/LC_MESSAGES/coreutils.mo flags=1(O_RDONLY) mode=0
82272 20:25:03.792815755 0 df (13093) > open
82273 20:25:03.792817694 0 df (13093) < open fd=-2(ENOENT) name=/usr/share/locale-langpack/en_US.UTF-8/LC_MESSAGES/coreutils.mo flags=1(O_RDONLY) mode=0
82274 20:25:03.792818888 0 df (13093) > open
82275 20:25:03.792820561 0 df (13093) < open fd=-2(ENOENT) name=/usr/share/locale-langpack/en_US.utf8/LC_MESSAGES/coreutils.mo flags=1(O_RDONLY) mode=0
82276 20:25:03.792821747 0 df (13093) > open
82277 20:25:03.792823340 0 df (13093) < open fd=-2(ENOENT) name=/usr/share/locale-langpack/en_US/LC_MESSAGES/coreutils.mo flags=1(O_RDONLY) mode=0
82278 20:25:03.792824505 0 df (13093) > open
82279 20:25:03.792826178 0 df (13093) < open fd=-2(ENOENT) name=/usr/share/locale-langpack/en.UTF-8/LC_MESSAGES/coreutils.mo flags=1(O_RDONLY) mode=0
82280 20:25:03.792827357 0 df (13093) > open
82281 20:25:03.792828940 0 df (13093) < open fd=-2(ENOENT) name=/usr/share/locale-langpack/en.utf8/LC_MESSAGES/coreutils.mo flags=1(O_RDONLY) mode=0
82282 20:25:03.792830116 0 df (13093) > open
82283 20:25:03.792831685 0 df (13093) < open fd=-2(ENOENT) name=/usr/share/locale-langpack/en/LC_MESSAGES/coreutils.mo flags=1(O_RDONLY) mode=0
82306 20:25:03.792981934 0 df (13093) > open
82307 20:25:03.792989333 0 df (13093) < open fd=3(<f>/usr/lib/x86_64-linux-gnu/gconv/gconv-modules.cache) name=/usr/lib/x86_64-linux-gnu/gconv/gconv-modules.cache flags=1(O_RDONLY) mode=0
Handy (like dtruss).
Now formatting it a little:
# sysdig -p "%fd.num %fd.name" "evt.type=open and proc.name=df"
3 /etc/ld.so.cache
3 /lib/x86_64-linux-gnu/libc.so.6
3 /usr/lib/locale/locale-archive
3 /etc/mtab
3 /usr/share/locale/locale.alias
3 /usr/lib/x86_64-linux-gnu/gconv/gconv-modules.cache
Two problems:
# sysdig "evt.type=open and proc.name=df and evt.failed=true"
1228 20:33:31.575433825 0 df (13152) < open fd=-2(ENOENT) name=/usr/share/locale/en_US.UTF-8/LC_MESSAGES/coreutils.mo flags=1(O_RDONLY) mode=0
1230 20:33:31.575437147 0 df (13152) < open fd=-2(ENOENT) name=/usr/share/locale/en_US.utf8/LC_MESSAGES/coreutils.mo flags=1(O_RDONLY) mode=0
1232 20:33:31.575440240 0 df (13152) < open fd=-2(ENOENT) name=/usr/share/locale/en_US/LC_MESSAGES/coreutils.mo flags=1(O_RDONLY) mode=0
1234 20:33:31.575443329 0 df (13152) < open fd=-2(ENOENT) name=/usr/share/locale/en.UTF-8/LC_MESSAGES/coreutils.mo flags=1(O_RDONLY) mode=0
[...]
They seem to vanish when using formatting. I did not see an explanation in the User Guide.
It should be possible to do something like
evt.arg.data contains "\x48\x45\x4c\x4c\x4f"
brendan$ sysdig -c topfiles_time
error creating the process list
This was confusing as I forgot that I wasn't root. Error message could say something like: "Error creating the process list: permission denied. (root user?)"
# sysdig -l | grep 'id '
proc.pid the id of the process generating the event.
thread.tid the id of the thread generating the event.
user.id user ID.
group.gid group ID.
Which one is not like the others? :-)
I don't know if there was a reason to pick "user.id" instead of "user.uid", which would be more consistent with the others.
Changes in the machine list of users should be detected (for example by polling the user list every 30 seconds) and the list should be updated in the libsinsp state.
Also, a new user list block should be added to the dump file if dump to disk is enabled. This means that the dump file read code should handle user list blocks in the middle of event blocks.
The full error message:
$ sudo sysdig
error opening device /dev/sysdig0. Make sure you have root credentials and that the sysdig-probe module is loaded.
Installation did fail to install linux headers. Any advice?
the 64bit linux does some magic to run 32bit binaries. See:
http://stackoverflow.com/questions/3305350/how-do-32-bit-applications-make-system-calls-on-64-bit-linux
the CONFIG_IA32_EMULATION kernel flag
The result with our current driver is that the driver is uncapable of detecting and interpreting 32bit syscalls, generating a bunch of garbage and sometimes crashing the system.
How to replicate:
install skype on a 64bit fedora following these instructions http://www.unixmen.com/how-to-install-skype-on-fedora-18-64bit/ and capture its activity.
Some parameters (like "${CMAKE_CURRENT_BINARY_DIR}" and "${PROJECT_SOURCE_DIR}/common") are passed to CMake commands in your build scripts without enclosing them by quotation marks. I see that these places will result in build difficulties if the contents of the used variables will contain special characters like semicolons.
I would recommend to apply advices from a wiki article.
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.