abap-logger / abap-logger Goto Github PK
View Code? Open in Web Editor NEWABAP Logging as painless as any other language
License: MIT License
ABAP Logging as painless as any other language
License: MIT License
In our systems, I added an optional parameter to create_log. The logic in create_log is then:
if retention_period is not initial.
lo_log->header-aldate_del = sy-datum + retention_period.
endif.
i need to know how to use something like this
https://www.sapalles.com/2014/10/24/add-extra-custom-fields-to-application-log/
where I can insert a new column in between type and messages
Hello ABAP-Logger team,
I find myself often copying a method to display logs from mutliple ABAP Logger instances. To be fair - I had the same problem when using SAP's cf_reca_message_list (mind you - I couldn't find a display method at all there).
Imagine a situation where the programm is processing multipe sales orders and calling a BAPI. The messages from the BAPI may or maynot include the sales order. To handle this, I create an ABAP Logger instance per sales order and use the sales order as the external identification nr (ABAP Logger calls this the desc). This is not a problem for a batch job, unless the program should be executed interactively and the BAL Logs also be displayed to an interactive user - here the display method provided by ABAP-Logger is no longer adequate, as it only displays the messages form one instance (which makes sense).
In my most current example I've created a local class lif_bal_log / lcl_bal_log which creates multiple instances of ABAP Logger and saves the log handle into a member attribute mt_log_handles.
My suggestion is to create a collection class, which can adds the instances to a table.
Then when the collection display_logs method is called, it could create a table of log handles and excute the coding.
Alternatively the factory class could remember all instances / log handles it creates. But i don't personally like this approach. A factory should problably only be a factory...
Thanks
Martin
` METHOD lif_bal_log~display_logs.
DATA: ls_display_profile TYPE bal_s_prof.
IF mt_log_handles IS INITIAL.
RETURN.
ENDIF.
CALL FUNCTION 'BAL_DSP_PROFILE_STANDARD_GET'
IMPORTING
e_s_display_profile = ls_display_profile.
ls_display_profile-head_size = 125 .
ls_display_profile-tree_size = 25 .
IF ls_display_profile-mess_fcat IS NOT INITIAL.
SORT ls_display_profile-mess_fcat BY no_out ASCENDING col_pos DESCENDING.
ENDIF.
CALL FUNCTION 'BAL_DSP_LOG_DISPLAY'
EXPORTING
i_s_display_profile = ls_display_profile
i_t_log_handle = mt_log_handles
EXCEPTIONS
profile_inconsistent = 1
internal_error = 2
no_data_available = 3
no_authority = 4
OTHERS = 5.
IF sy-subrc <> 0.
MESSAGE ID sy-msgid TYPE 'S' NUMBER sy-msgno
WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4 DISPLAY LIKE sy-msgty.
ENDIF .
ENDMETHOD.`
Hi Eric,
Thanks for you development,
today, when i tried to do, some errors have caused.
its the code what i had written
REPORT ZTA_TEMP2.
DATA: log TYPE REF TO zcl_logger.
BREAK-POINT.
CREATE OBJECT log.
log = zcl_logger=>new( object = 'ZTAMER'
subobject = 'ACCOUNTING'
desc = 'Stuff imported from legacy systems' ).
log->e( 'You see, what had happened was...' ).
BREAK-POINT.
LOG->POPUP( ).
and error is -
Error in the ABAP Application Program
The current ABAP program "ZCL_LOGGER====================CP" had to be
terminated because it has
come across a statement that unfortunately cannot be executed.
A function module was called incorrectly.
1 method POPUP.
2 * See SBAL_DEMO_04_POPUP for ideas
3
4 DATA: profile TYPE bal_s_prof.
5 CALL FUNCTION 'BAL_DSP_PROFILE_POPUP_GET'
6 IMPORTING
7 e_s_display_profile = profile.
8
CALL FUNCTION 'BAL_DSP_LOG_DISPLAY'
10 EXPORTING
11 i_s_display_profile = profile
12 i_t_log_handle = me->handle.
13
14 endmethod.
thank you for reply
Hi!
Structures BAPIRET1 and BAPIRET2 have a field with name MESSAGE.
The CS operator will give the count 8. not 7:
IF 'TYPE,NUMBER,ID,MESSAGE_V1,MESSAGE_V2,MESSAGE_V3,MESSAGE_V4,' CS |{ component-name },|.
bapi_count = bapi_count + 1.
ENDIF.
Hi,
first of all this is an amazing logger thanks for all the work. My current project has a requirement to change the externalId of the log (desc) you supply to create_log. Is there any way to achieve this? I'm not even sure if you can do that at all...
any help on this is greatly apprechiated!
Regards
Alex
I installed ABAP-Logger yesterday.
If I try to double click the method ZIF_LOGGER~ADD (or any other implemented interface method) nothing happens. I looked the code in source view and I see this:
---------------------------------------------------------------------------------------+
| Instance Private Method ZCL_LOGGER->ADD
+-------------------------------------------------------------------------------------------------+
+--------------------------------------------------------------------------------------
method add.
data: detailed_msg type bal_s_msg,
exception_data_table type tty_exception_data,
free_text_msg type char200,
ctx_type type ref to cl_abap_typedescr,
...
I think it should be:
method ZIF_LOGGER~ADD.
Can it happen because an AbapGit version change? I use AbapGit 1.97.0.
Btw, somehow it works anyway :)
Some BAPI (such as BAPI_REQUIREMENTS_CREATE
) return a bapireturn1
table
The method validate( ) of a model class performs checks and returns an object with all the errors found. (see https://www.martinfowler.com/articles/replaceThrowWithNotification.html for the pattern description).
I may display the messages to the users but I may also log them.
the model class could use a zcl_logger instance but the model does not know whether we are in a validating user input (with one call per PAI/PBO cycle) or processing some code which need to be logged for good.
As of today, I get the messages, loop on them and log each one of them.
Validation( ) method returns an object that implements zif_loggable_object. The upper-level code may log these message in one instruction such as
data(notification) = model->validate( ).
if notification->has_error( ) = abap_true.
logger->add_loggable_object( notification ).
endif.
Please do not hesitate to provide feedback on this proposition, the naming or anything,
Thanks,
Hi,
first I want to say, that I really like the flexibility which this project/class brings.
However I would like to know, how you would like others to use this? My question is based on the Licence you choose for this project. The GPL dictates that every project which uses GPL licenced code will also become GPL licensed. In the projects where I work this is not intended, so practically I cannot use your class there.
Did you intend knowledge sharing with this project? In that case the GPL is totally fine. But if you had in mind that others can use this component in their customer projects (what I would love to do) the GPL mostly is a blocker for customers, because it´s kind of ("infecting" as I was told. In that case you might consider to switch to the BSD licence.
Best Regards
Alex
Suggest adding the above helpers to the interface. There is a clear workaround with export_to_table
but is need several code lines which is inconvenient fr a status check.
If agreed I can PR :)
be able to attached extra fields on error line save to database and be able to view the fields on the display by custom transaction in alv like now but to be searchable.
find a resource https://oprsteny.cz/?p=249
also vidyadharg upload a version that says is working but the new method are missing from github.
#71
I often use chained exceptions, making use of the previous
standard attribute. This is a best practice explained here:
https://github.com/SAP/styleguides/blob/master/clean-abap/CleanABAP.md#use-sub-classes-to-enable-callers-to-distinguish-error-situations
Example:
TRY.
b = a / 0.
CATCH cx_divide_by_zero INTO DATA(exc).
RAISE EXCEPTION TYPE zcx_myapp
EXPORTING
previous = exc.
ENDTRY.
This means that the actual relevant description of the exception is at he bottom level of the chain, accessible via the previous
attribute.
It would be great to have an option when adding an OO exception. That option would decide what to register:
Something recursive should do the trick. I can attempt to do a PR if you believe this makes sense.
Thanks,
Nuno
Hi Guys
Comparing with other modern languages, I think we should not have two methods , one to create log with new and other to open it . One should think of a simple method like get() which returns the log object if it does not exists based on the desc ( external number ) field.
Also, desc field should not be meant for description but it is close to being like log handle. generally in Java or Python, the logger takes class name or prgram name to log all its messages, and thats how one would know in a log file about where the log comes.
The desc should by default have sy-repid as input but it could be different based of complex application like a transaction id throughout a transaction.
The logger interface has 3 attributes - as of now:
data handle type balloghndl read-only .
data db_number type balognr read-only .
data header type bal_s_log read-only .
Shouldn't they be in the class for the bl-log-class?
Probably no other log class for this interface will need those attributes.
What do you think?
I noticed all my commits were individually merged on my last PR.
No problem if this is intentional, but if not then I would suggest using squash commits in most cases. It keeps the commit history cleaner as all the commits of a PR are rolled up into a single commit and we won't have all the minor work in progress commits in the history.
It looks like the best practice for repo is to put source files in a src folder. Examples:
It would allow us to store documentation in a separatated /docs folder
abapGit store the source folder in .abapgit.xml. The downside is that abapGit does not handle the change. Repo needs to be uninstalled and re-installed
I think it's best to wait until the PR queue is empty.
Are looking for new maintainers or do you still maintain this repository, even you don't develop ABAP anymore?
Some classes use all lower case while others are formatted with upper case keywords. It would be helpful for maintainers to settle on one setting (and then set abaplint rule keyword_case accordingly).
The installation instructions state that sub-object LOGGER should be created for object ABAPUNIT.
I see that the unit test class for ZCL_ALOG_BAL_LOGGER uses ZALOG_TEST and SUB as object and sub-object respectively. Does that mean the sub-object LOGGER does not have to be created (SAP complains about namespace), and that we should instead create ZALOG_TEST and SUB?
The self-reference return variable is not set when a table of BAPI return messages is logged.
It can be fixed by simply adding a line "self = me."
I have implemented it, just need to go through the hoops to create a pull request (sync to internal gitlab, sync to local git, sync to github fork, create a pull request). Not a small task for a git beginner such as myself!
Title
Hello guys,
i've encountered a weired issue where if you want to log a free text and supply a context the BAL function returns an exception (which are not cought at all in the logger btw) reporting inconsistency in the context. This is because the type description will return the base structure but not the one you supplied zcl_logger.clas.abap#L271..
If I supply the context directly it works flawless without any problems. Is there a reason for supplying the formatted_context in zcl_logger.clas.abap#L407?
Regards
Alex
Thanks for providing your solution in Github.
However, I found the solution to be somewhat redundant to the SAP-Standard. You don't have to use the BAL_LOG-BAPIs. SAP provides a big number of logger classes, that can be used in a similar way, e.g. the class cl_bal_logger:
TRY.
cl_bal_logger=>initialize( EXPORTING i_log_object = NEW cl_bal_logobj( i_log_object = 'FOO' ) ).
cl_bal_logger=>add_errortext( i_errortext = 'An error occurred' ).
cl_bal_logger=>add_statustext( i_statustext = 'A nice status message' ).
cl_bal_logger=>add_msg( i_probclass = if_sbal_logger_config=>c_probclass_none ).
cl_bal_logger=>save_to_db( ).
CATCH cx_bal_exception INTO DATA(log_exception).
ENDTRY.
This might be an alternative for those, who do not want to download 3rd-Party-Solutions to their SAP-System.
Happy Coding!
Hello!
Callback is very usefull for viewing messages, but additional parametr is needed. I think it will be good to add new optional parametr it_par TYPE bal_t_par
to methods ADD, A, E, W, I, S.
Thanks!
I'd like to be able to log any deep structure or table (...and not only BAPIRET2, BDCMSGCOLL and HRPAD_MESSAGE).
My use case is to log the request and response structure of a SOAP web service call (which often consists of table types) if it fails.
I could imagine converting structures and tables to a JSON like string, pretty print it (with line breaks) and logging it line by line.
What do you think?
On the system where I'm using ABAP-Logger there is a customer exception class which carries a message table (bapiret2_t). When unexpected errors in a BAPI or similar occur, an instance of a exception class is thrown and the message table is passed as a parameter. I think other SAP customers would also have a similar exception class.
Now obviously zcl_logger can't be dependant on a customer exception class. But I was thinking a Z-BADI definition would be nice.
Current I've implemented an implizit enhancement (I want ABAP-Logger support without conflicts) at the end of the add method. But I feel a Z-BADI would be better. I don't know if ABAP Git can carry a BADI Definition though.
ENHANCEMENT 2 zxxx_enh_logger.
IF msg_type->type_kind <> cl_abap_typedescr=>typekind_oref.
RETURN.
ENDIF.
DATA customer_error_instance TYPE REF TO zcx_my_abstract_exception_class.
IF obj_to_log IS INSTANCE OF zcx_my_abstract_exception_class.
customer_error_instance ?= obj_to_log.
DATA(messages) = customer_error_instance->get_messages_recursively( ). "customer method!!!
IF messages IS NOT INITIAL.
me->add(
obj_to_log = messages
context = context
callback_form = callback_form
callback_prog = callback_prog
callback_fm = callback_fm
type = type
importance = importance ).
ENDIF.
ENDIF.
ENDENHANCEMENT.
What are your thoughts?
Structure PROTT
Short desc Log for Picking Report
This has a similar challenge as HRPAD as it's only present in ECC i belive, since it's SD specific. To get around this we can define it as a local type.
Hi,
I would suggest to change to following line:
if obj_to_log is initial.
https://github.com/epeterson320/ABAP-Logger/blob/master/zcl_logger.clas.abap#L210
to
if obj_to_log is not supplied.
Otherwise a message is created if an empty return table is passed to the method.
Regards,
Timo
Hello,
via the automated Test run in our System, the following Methods of LCL_TEST of ZCL_LOGGER fail:
It's obviously that some kind of language conflict exists here, the system language is German (D), but the Logger Class is executing the Tests in English. By changing the sy-langu to German during Debugger Session, the Tests will pass.
Code where the false Text Components are set:
By switching Logon Language to English, tests also pass but it would be nice to stay in German Environnement for that.
My question is now what do I have to do to resolve this issue? On the first try I didn't found the Text Elements to translate them...
Let's start a discussion. I am looking for a solution to get the last used logger object. Normally I initialize the logger class in the constructor of a using class, assign it to a private instance attribute and use it in the methods of the using class.
Sometimes you want to use the same logging object in static methods of the class or in other classes in the context of the same program. I think it is not a good idea to pass the reference to the logger by a parameter.
As ABAP does not offer dependency injection I would suggest to add some kind of static method like "get_last". When an instance of ZCL_LOGGER is created we could save this reference in a static attribute of ZCL_LOGGER, and return it if "get_last" is called. What do you think about this?
Hi All,
I realized method ZIF_LOGGER~EXPORT_TO_TABLE does not generate a message table from logged exception classes.
The method uses function module 'BAL_LOG_MSG_READ' that cannot read an exception based message.
How to replicate:
I believe something can be done with BAL_LOG_EXCEPTION_READ function but it's quite limited as well.
For my local system and scenario usage, the enhancement bellow was enough, didn't had much time to look further
DATA:
message_handles TYPE bal_t_msgh,
message TYPE bal_s_msg,
bapiret2 TYPE bapiret2,
exception_log TYPE bal_s_excr,
exception_msg TYPE char255.
FIELD-SYMBOLS <msg_handle> TYPE balmsghndl.
message_handles = get_message_handles( ).
LOOP AT message_handles ASSIGNING <msg_handle>.
CLEAR bapiret2.
CALL FUNCTION 'BAL_LOG_MSG_READ'
EXPORTING
i_s_msg_handle = <msg_handle>
IMPORTING
e_s_msg = message
EXCEPTIONS
OTHERS = 3.
IF sy-subrc IS INITIAL.
MESSAGE ID message-msgid
TYPE message-msgty
NUMBER message-msgno
INTO bapiret2-message
WITH message-msgv1 message-msgv2 message-msgv3 message-msgv4.
bapiret2-type = message-msgty.
bapiret2-id = message-msgid.
bapiret2-number = message-msgno.
bapiret2-log_no = <msg_handle>-log_handle. "last 2 chars missing!!
bapiret2-log_msg_no = <msg_handle>-msgnumber.
bapiret2-message_v1 = message-msgv1.
bapiret2-message_v2 = message-msgv2.
bapiret2-message_v3 = message-msgv3.
bapiret2-message_v4 = message-msgv4.
bapiret2-system = sy-sysid.
APPEND bapiret2 TO rt_bapiret.
ELSE.
CALL FUNCTION 'BAL_LOG_EXCEPTION_READ'
EXPORTING
i_s_msg_handle = <msg_handle>
i_langu = sy-langu
IMPORTING
e_s_exc = exception_log
e_txt_msg = exception_msg
EXCEPTIONS
log_not_found = 1
msg_not_found = 2
OTHERS = 3.
IF sy-subrc = 0.
bapiret2-type = message-msgty.
bapiret2-log_no = <msg_handle>-log_handle.
bapiret2-log_msg_no = <msg_handle>-msgnumber.
bapiret2-message = exception_msg.
APPEND bapiret2 TO rt_bapiret.
ENDIF.
ENDIF.
ENDLOOP.
Thanks :)
When you supply the auto_save parameter via the constructor, it is ignored. I passed auto_save = abap_true and then auto_save is turned falsely to false (because it is supplied).
I think a solution could look like this:
IF auto_save IS SUPPLIED.
r_log->auto_save = auto_save.
ELSE.
IF object IS NOT INITIAL AND subobject IS NOT INITIAL.
r_log->auto_save = abap_true.
ENDIF.
ENDIF.
Hello,
when I execute the ATC checks in English I get an error message 'Caution: The text pool is inconsistent. Edit the text elements'. Is possible to remove these text pool entries and resolve the ATC error?
<TPOOL> <item/> <item/> <item/> .... </TPOOL>
there are however a lot of tline / tdlines which are part of the long text documentation? I'm not sure if the Text pool is somehow connected to this?
<LINES> <TLINE> <TDFORMAT>U1</TDFORMAT> <TDLINE>&FUNCTIONALITY&</TDLINE> </TLINE>
Thanks
Martin
Hi,
here's my litte sample sample report that shows the issue:
REPORT ZLOGTEST.
DATA: log TYPE REF TO zcl_logger.
log = zcl_logger=>new( object = 'TEST'
subobject = 'TESTSUB1'
desc = 'Test' ).
DATA(l_flight) = VALUE sflight( carrid = 'ZP' connid = '77' fldate = sy-datum ).
MODIFY sflight FROM l_flight.
...
*Something bad happened
log->e( 'Oh oh, there was a problem. Could not save sflight.' ).
rollback work.
write: / 'End.'.
The problem is that the logged message is not saved.
I cannot find the message in transaction SLG1.
Because of the rollback work statement all database changes including the log are discarded.
However, I found a simple solution to this problem.
In method ADD of class ZCL_LOGGER the function module BAL_DB_SAVE is called.
If you set the parameters I_2TH_CONNECTION and I_2TH_CONNECT_COMMIT to true it works as expected. E.G:
CALL FUNCTION 'BAL_DB_SAVE'
EXPORTING
i_t_log_handle = log_handles
I_2TH_CONNECTION = abap_true
I_2TH_CONNECT_COMMIT = abap_true
IMPORTING
e_new_lognumbers = log_numbers.
The trick is to tell the function module to use a secondary database connection to save the log.
C.f. http://help.sap.com/abapdocu_740/en/abenopensql_multiconnect.htm
This way the main logical unit of work is rolled back, but the log is still saved.
Should the logger always use the 2nd connection? Or should the logger have an option to turn on the usage of the sec. connection?
What do you think?
Cheers,
Thomas
See details here: https://blogs.sap.com/2019/05/06/introducing-apack-a-package-and-dependency-manager-for-abap/
The ABAP Environment on SAP Cloud Platform will support a Maven like dependency management and therefore a new interface needs to be implemented.
The latest zcl_logger.slnk file has the method EXPORT_TO_TABLE, but the latest zcl_logger.abap is missing that method.
I think those two files should be in sync?
Hello everyone,
i've just setup abapGit and i'm trying to import this repo as offline from the master zip but it's giving me this error:
Error from SEO_CLASS_CREATE_COMPLETE. Subrc = 5
OTR-Based Exception of Class: ZCX_ABAPGIT_EXCEPTION
I've created a package and transport for the repo nothing else
It would be nice if we could provide the expiry date for log entries. The expiry date is an important attribute for transaction SLG2 which deletes expired logs.
Suggestion: I can add expiry_date as parameter (data element: ALDATE_DEL) for the methods new() and open() and set it on SLG header. What do you think about this?
Hi,
parameter Context has a "simple" data type which only accepts character like data so gives an error for a number like fields.
The following code gives design time an error.
Solution: change parameter context from simple type to any
DATA lv_context TYPE sflights.
DATA logger TYPE REF TO zif_logger.
logger = zcl_logger_factory=>create_log( object = 'ABAPUNIT'
subobject = 'LOGGER'
desc = 'LOGGER Demo' ).
MESSAGE E000(oo) WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4 INTO DATA(dummy).
logger->add( context = lv_context ).
Hello,
Is there a nice way to use ABAP-Logger along with OData exceptions?
OData exceptions is implemented something along the lines of:
IF i_msg_type IS NOT INITIAL AND i_msg_text IS NOT INITIAL.
me->context->get_message_container( )->add_message_text_only(
EXPORTING
iv_msg_type = i_msg_type
iv_msg_text = i_msg_text
iv_add_to_response_header = ls_add_to_header
).
IF i_msg_type = 'E'.
me->has_errors_flag = abap_true.
ENDIF.
ENDIF.
IF i_raise IS INITIAL.
RETURN.
ENDIF.
IF i_is_tech = abap_true.
RAISE EXCEPTION TYPE /iwbep/cx_mgw_tech_exception
EXPORTING
message_container = me->context->get_message_container( ).
ELSE.
RAISE EXCEPTION TYPE /iwbep/cx_mgw_busi_exception
EXPORTING
message_container = me->context->get_message_container( ).
ENDIF.
In method EXPORT_TO_TABLE of class ZCL_LOGGER, there is a MESSAGE statement in line 29 that generates a short dump whenever a message with no reference to a message class was used. Therefore, the method is not useful for any case no message classes are used.
I performed a manual correction in my system just like this:
IF message-msgty IS NOT INITIAL.
MESSAGE ID message-msgid
TYPE message-msgty
NUMBER message-msgno
INTO bapiret2-message
WITH message-msgv1 message-msgv2 message-msgv3 message-msgv4.
ENDIF.
Its really not so important...but it think the tests should run in any language.
zcl_logger->lcl_test->can_log_batch_msgs() + zcl_logger->lcl_test->can_log_chained_exceptions
latest version contains new syntax like conv
and new
. Would you mind if I downport ? (I have 731)
Method POPUP is not working due to the attribute ME->HANDLE sent to function module BAL_DSP_LOG_DISPLAY. A handle table is expected, instead of a single handle. The correction applied was this:
method popup.
data: profile type bal_s_prof,
t_handle type BAL_T_LOGH. " Correction
call function 'BAL_DSP_PROFILE_POPUP_GET'
importing
e_s_display_profile = profile.
append me->handle to t_handle. " Correction
call function 'BAL_DSP_LOG_DISPLAY'
exporting
i_s_display_profile = profile
i_t_log_handle = t_handle. " Correction
endmethod.
SAPLINK is kind of outdated and abapGit is a great tool. Easy to install and use. Would be great if you would migrate to abapGit for easy installation purpose of the software.
Cheers
Hendrik
Great - love the library.
Heres a small issue - bapi_order_return, rcomp and prott aren't included in SAP SolutionManager. They might be missing on BW too - I haven't checked there.
This leads to syntax errors, which while note being very easy to solve (I commented out the appropriate code blocks and tests). I think these could be solved with a little dynamic ABAP. I'd be willing to create a fix - but I'm not sure if the changes are desired...
Thanks
Hello! It needs to correct method get_message_handles in the line 14.
It should be <f>-lowtype = msgtype
instead of <f>-lowtype = 'E'
. Otherwise method has_warnings returns the same result as method has_errors.
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.