How to debug web development in Google Application Script? - debugging

I am testing/learning webhook. How to send, receive it. So I thought I would use GAS.
I have this simple script and I wonder why Logger does not work. In Projects/Executions I can see that the script doPost was executed but no logs. Email was sent and the script returned the value.
using old, Legacy Editor (no idea how to get the new one)
in Menu-Resources-Cloud Platform Project is said "This script has an Apps Script-managed Cloud Platform project."
when I open the project in editor I get this message "This project is running on our new Apps Script runtime powered by Chrome V8."
exception logging set to "exceptionLogging": "STACKDRIVER" is set to default
I tried console.log(e); but it did not work for me.
function doPost(e) {
Logger.log("I was called")
if(typeof e !== 'undefined'){
Logger.log(e.parameter);
Logger.log("I was called 2")
MailApp.sendEmail({
to: "radek#gmail.com",
subject: "Call Sucessful",
htmlBody: "I am your <br>" +
JSON.stringify(e)+ "<br><br>" +
JSON.stringify(e.parameters)
});
}
return ContentService.createTextOutput(JSON.stringify(e))
}
Question1: Can I make Logger work?
Question2: I would like to see accepted data in Debugger, is that possible?
Question3: Is there any way the GAS pushes the data it received to my web browser. Of course the browser is NOT sending the data.
Question4: No related to the topic but ... Would you know what I need to do in order to be able to use new Editor?

If you want your own custom log information to go to Stackdriver, then you need to create a Google Cloud Platform project, and associate that GCP project with your Apps Script project.
First create a new GCP Project:
Go to your GCP dashboard:
https://console.cloud.google.com/home/dashboard?authuser=0
In the blue bar at the top, there is a drop down menu for project names. Click that, and a dialog should appear with a button to create a new project.
Create a new Google Cloud Platform project.
Copy the Project Number.
Go back to the Apps Script editor.
From the legacy Apps Script editor, click the "Resources" menu.
Click Cloud Platform project.
Paste in the Project Number and click the button.
Now, any console.log() statements you have will send the logs to Stackdriver.
And Stackdriver can be viewed in your browser.
Note: Some people set up their own logging system to log information from server side Apps Script code to a Google Sheet. There are some open source repos that are available.
The new code editor does have a "built-in" way to log server side information to a log pane code editor window. But, of course this assumes that you are running code from the code editor. This new feature avoids the need for changing browser tabs to see your logging output. I don't know of any way to log server side info to your browser console. You could save log info into an object, and then send it back to the client after the server code completed, and then log everything in the console.
The way that it might be possible to get logging information depends on how the code was originally triggered.
From code editor
From a user using your app
From a Http Request to your Web App
Logging in Apps Script works differently depending upon:
run time version being used - V8 or DEPRECATED_ES5 - Set in appsscript.json file or through the "Run" menu in the Legacy editor, Set in "Settings" in new IDE - New Apps Script projects default to V8 so chances are your project is using V8.
Is your Apps Script project associated with a Google Cloud Platform
(GCP) default or standard project
Is exception logging set to "exceptionLogging": "STACKDRIVER" - Set in appsscript.json file - Default is always to include it - Probably already correct unless you deleted it.
Using either Logger.log or console.log
Using console.log in the server ".gs" file or client side ".html"
file. console.log can be used in both server and client side code
but the log print out goes to different places. You can't see logs
in the browser dev tools from a console.log statement in your
server code. If you use console.log in server side .gs files, and the Apps Script project is not associated with a standard GCP project, then the log only gets sent to your "Executions." I believe that the only way that you can get your logs sent to Stackdriver is by using a standard GCP project. The problem with that, is that you only have so many GCP projects that you can use without requesting an increase in your quota.
Plus there may be issues (bugs) depending upon how you have logging set up and other factors.
For example:
https://issuetracker.google.com/issues/134374008

As lots of people specified, you can use console.log for this.
However, I also work with webhooks from time to time. And I find it much more comfortable to debug directly into google spreadsheets, using code like this
function doPost(e) {
log('# doPost', JSON.stringify(e));
try {
// Some webhook-processing logic here
if(e.parameter.action == 'test-error') {
item.something = nothing;
}
if(e.parameter.action == 'test-log') {
log('# custom log', 'Some data');
}
} catch(error) {
log('# error', JSON.stringify([error, error.stack]));
}
}
function log(event, message){
SpreadsheetApp.getActive().getSheetByName('Log').appendRow([new Date(), event, message])
}
Example spreadsheet:
https://docs.google.com/spreadsheets/d/144i9pxDIB_C8ZRZ-6vd9DiPIw8Rt85hTtVoqk7dtHQg/edit?usp=sharing
You can trigger logging by something like this
curl -X POST https://script.google.com/macros/s/AKfycby3EoaQ8DOt8H_Mc4vjH6JZkhsaAwYHk_sa9HE5Be3qVo0Ym0b2/exec?action=test-error
or
curl -X POST https://script.google.com/macros/s/AKfycby3EoaQ8DOt8H_Mc4vjH6JZkhsaAwYHk_sa9HE5Be3qVo0Ym0b2/exec?action=test-log
You can use same log for your custom logging of some intermediate variable during webhook resolution.
The reason I prefer this over standard stackdriver logging is that google sheets are more explicit and easier to manage.

You can use console.log() to see things within "My Executions".

Related

Google Analytics not sending any events or custom dimensions data to dashboard

Scenario:
I am using this module: https://www.drupal.org/project/google_analytics version 3.1
It is using Google Analytics 4. Drupal version 8.9.x
We followed the documentation https://developers.google.com/analytics/devguides/collection/gtagjs/custom-dims-mets to create some custom dimensions and added in the Google Analytics configuration accordingly.
When view the page source, I see code is added there:
gtag("config", "G-MESUREMENT-KEY", {
"custom_map": {
"dimension1":"user_company",
"dimension2":"user_role",
"dimension3":"user_badge_access"
}
}
);
gtag("event", "custom", {
"user_company":"TEST Company",
"user_role":"authenticated, member_administrator, administrator",
"user_badge_access":"Office"
}
);
Using some Chrome GA debugger "GTM/GA", I see parameter is passing there. In the request "Pay Load" of Chrome debugger it shows its sending the values:
en=page_view&ep.anonymize_ip=true
en=page_view
en=custom&ep.user_company=Surface%20Oncology&ep.user_role=authenticated%2C%20member_administrator%2C%20administrator&ep.user_badge_access=Office
BUT I don't see the data when I open DebugView in the GA dashboard! And Interesting part is, some chrome debugger like "Google Analytics Debugger 2.8" when enabled, which seems open a debugger and connect to GA dashboard, DebugView is showing the events and parameters data. So there must be something which restricting or refusing to connect with GA Dashboard to push the data.
Reads lot of documentation, did lot of test but failed to find a reason for that. The site is fully login protected but event /user/login page which is accessible to all, not sending the data at all.
If some one can shed some light on the issue, it will really really help for me. Thanks in advance.
Actually this is my mistake of my understanding. All data is pushing to GA dashboard no confusion. The reason why I don't see data when creating a comparison report based on custom dimension parameters is due to "scope" difference.
So if you want to create a report based on event scoped parameters, please go to Engagement->Events, and if you want to create a report based on user scoped parameters, please go to Audience tab, but user scoped report will not show data if captured users record is less than 10.
A documentation for reference: https://support.google.com/analytics/answer/2709828?hl=en

Form displays blank fields instead of DB data values

I have a from with a plugin that updates a record in the DB. I see the updated data in the record in the DB, but when i load the form the updated data does not show.
there are no business rules, the is no JS OnLoad event.
The record is inactive in the DB when the data is updated, but i don' think that should matter
Any ideas as to what I am overlooking?
You're correct that the changes should still save to an inactive record.
Under Advanced Settings > Administration > System Settings > Customization you can set "Enable logging to plug-in trace log" to "All".
Then in the plugin you can use the ITracingService to log messages, which are then visible in Advanced Settings > Plugin-In Trace Log.
You could log the fields' values before and after you set them to confirm that they're getting set.
Or, for a "quick and dirty" option store the fields' values before you set them, then after you set them, throw an InvalidPluginExecution exception containing the "before and after" values. The exception message will pop up right in the UI.
We'd be better able to analyze the issue if you post your code.
On a related note, when writing plugins I often separate the logic out into a Visual Studio Shared Project. I reference that project from a console app and the plugin assembly. The console app enables me to test and debug locally with full VS debugging capabilities before publishing the plugin. Of course there are certain things from the context that can be tricky to mock in the Console app, so your mileage may vary depending on the application.
There are also testing frameworks like FakeXrmEasy, but I have yet to try any of those.

How to make UILabel "live"?

I would like to add text to my app so when ever I want to change the text in Xcode, the text will also change for the user. From my understanding so far, if I want to change a UILabel, I would have to submit it to the AppStore again and the user would have to update the app in order to see the UILabel text change.
Is it possible for me to add text on the app when ever I want and it will update for the user automatically?
First you should consider the solution, that will be connecting your app to certain API service.
In other words, the service that will bring fresh data to your app, will be an API, that your code will connect to. After connection and getting response from server, data from it will be transferred to the user interface of your application.
For example - your code will be set to make requests from your app using URL, looking like this:
http://example.com/api/request/?id=100
For better imagination, if you would like to check, what this URL returns, you would type that URL to your browser. It would return some output - for example JSON, something like this:
{"label": "This is title"}
So your app (after some action, for example when a view is shown or a user taps a button) will establish connection to this URL, to be able to get this output and process it. So it will await some structure, that is needed to read by your program. In this case, the structure is a format of an output, that is JSON.
Then, your code will parse this output and gets result. So the result would be "This is title" and your UILabel would be updated with "This is title".
For URL connections and sessions, using swift3, the best choice to use is an Alamofire framework:
https://github.com/Alamofire/Alamofire
And this is very useful tutorial:
https://www.raywenderlich.com/121540/alamofire-tutorial-getting-started.
It explain, how to get an access to a service, that is capable to prepare your output (e.g. JSON), because your app will need to connect to it.
This tutorial is a solid guide, how to create a service like that.
You have to implement web services for this where your app will read data from some server, programmatically. And using this you can update your any type of data. I would suggest to read more about Objective C Basic, Web services, AFNNetworking, NSURLSession and all.

Download build drop from hosted Team Foundation Service

Using the hosted Team Foundation Service at tfs.visualstudio.com, one has the option in a Build Definition to "Copy build output to the server" which creates a zip of the drop folder that can be downloaded over https via team web access. I really need to download this drop automatically, so I can chain input to the next stage in my build pipeline.
Unfortunately, the drop URL is not obvious, but can be created using the TfsDropDownloader.
TL;DR - I can't get the TfsDropDownloader to work, I'm hoping someone else has used this tool or a similar method to succesfully download a drop from https://tfs.visualstudio.com
Using the command line TfsDropDownloader.exe I can do this:
TfsDropDownloader.exe /c:"https://MYPROJECTNAME.visualstudio.com/DefaultCollection" /t:"ProjectName" /b:"BuildDefinitionName" /u:username /p:password
...and get an empty zip file with the correct build label name of the last successful build e.g. BuildDefinitionName_20130611.1.zip
Running the source code in the debugger, this is because the URL that is generated for downloading:
https://tflonline.visualstudio.com/DefaultCollection/_apis/resources/containers/804/drop/BuildDefinitionName_20130611.1.zip
..returns a content type of application/json, which is unsupported. This exception is swallowed by the application, but not before the empty zip file is created.
Is it possible the REST API on Team Foundation Service has changed in some way so the generated URL is no longer correct?
Note that I am using the "alternate credentials" defined on my Team Foundation Service account (i.e. not my live ID) - using anything else gets me TF30063: not authorized.
I got it working by using alternate credentials, but I also had to access the REST API via a different path.
The current TfsDropDownloader builds a URL that looks like this:
https://project.visualstudio.com/DefaultCollection/_apis/resources/containers/804/drop/BuildDefinitionName_20130611.1.zip
This returns empty JSON whenever I try to use it. I'm definitely authenticated, because if I tweak the URL to:
https://project.visualstudio.com/DefaultCollection/_apis/resources/containers/804/drop
I get a nice JSON listing of every single file in the drop, but no zip.
From spying on the SSL traffic to https://tfs.visualstudio.com with Fiddler I saw that clicking the "Download drop as zip" link I can see that there is another endpoint at:
https://project.visualstudio.com/DefaultCollection/ProjectName/_api/_build/ItemContent?buildUri=vstfs%3a%2f%2f%2fBuild%2fBuild%2f639&path=%2Fdrop
...which does give you a zip. The "vstfs%3a%2f%2f%2fBuild%2fBuild%2f639" portion is the URL encoded BuildUri.
So I've changed my version of GetServerPath in the TfsDropDownloader source to do this:
private static string GetServerPath(TfsConnection collection, IBuildDetail buildDetail)
{
var downloadPath = string.Format("{0}{1}/_api/_build/ItemContent?buildUri={2}&path=%2Fdrop",
collection.Uri,
HttpUtility.UrlPathEncode(buildDetail.TeamProject),
HttpUtility.UrlEncode(buildDetail.Uri.ToString()));
return downloadPath;
}
This works for me for the time being. Hopefully this helps someone else with the same problem!

Effective way to debug a Google Apps Script Web App

I have had some experience writing container-bound scripts, but am totally new to web apps.
How do I debug (e.g. look at variable values, step through code etc) a web app? In a container bound script it was easy, because I could set breakpoints, use the apps script debugger - how do I go about this in a web page e.g. when I execute a doPost?
In his excellent book "Google Script", James Ferreira advocates setting up your own development environment with three browser windows; one for the code, one for the live view (in Publish, Deploy as web app, you are provided with a "latest code" link that will update the live view to the latest save when it is refreshed), and one for a spreadsheet that logs errors (using try/catch wrapped around bits of code you want to keep an eye on).
In Web Apps, even the most basic debugging of variables through Logger.log() does not work!
A great solution to have at least simple variable logging available is Peter Herrmann's BetterLog for Apps Script. It allows you to log into a spreadsheet (the same as your working spreadsheet or a separate one).
Installation is very simple - just add an external resource (see the Github readme) and a single line of code to override the standard Logger object:
Logger = BetterLog.useSpreadsheet('your-spreadsheet-key-goes-here');
Remember, that the spreedsheet that you give here as a parameter will be used for the logging output and thus must be writable by anybody!
BetterLog will create a new sheet called "Log" in the given spreadsheet and will write each log call into a separate row of that sheet.
So, for me, I debug the front-end using inspector, I haven't found a way to step through code yet, but you can use 'debugger' in your javascript (along with console.log) to stop the code and check variables.
to debug the backend, what I've been doing is to write my functions like
function test_doSomething(){
payload = "{item1: 100, item2: 200}" //<- copy paste from log file
backend_doSomething(payload)
}
function backend_doSomething(payload){
Logger.log(payload)
params = JSON.parse(payload)
...
}
Then after refreshing your project on the backend, you can look at executions, grab the payload from the log file, and paste it into your test_doSomething() function.
From there, you are re-creating the call that you want to debug and you can run that, stepping through the backend code as usual.

Resources