Logging In PHP

A quick note: here’s how to write a line of text into logging on the PHP runtime:

syslog(LOG_INFO, "Log Text: " . $variable_to_log);

The first argument can be replaced with standard PHP logging levels, such as LOG_WARNING.

A reminder: App Engine ignores calls to openlog() and closelog() . While you can still call these functions (for instance if you have legacy code), they will not affect logging.

Counting Entities In The App Engine Datastore.

In SQL, the COUNT statement is available for counting the number of rows returned by a SELECT query. Here’s an example:

SELECT COUNT(*) FROM foods WHERE name="apple";

Unfortunately, the App Engine datastore offers no equivalent to the COUNT statement. To count the number of entities, an application has two options:

  1. Count the entities in a separate counter as they’re added to the datastore. For superior performance, the counter can be sharded and temporarily stored in memcache.
  2. Query for entities and count the number of entities returned. To help speed up this query, a keys-only request can be configured. However, this option can be slow and expensive.

Mapping Servlets To App Engine XMPP Requests

Here’s an example of how to configure servlets to accept XMPP requests. The XML below should be added to the web.xml file in the /war/WEB-INF directory.

This XML snippet configures three servlets: ChatServlet (handles inbound XMPP chat messages), PresenceServlet (handles requests for the application’s presence information, and presence info for other clients) and SubscribeServlet (when other XMPP users grant the application access to their presence information).

<!-- Handles the chat part of XMPP. -->
<servlet>
    <servlet-name>Chat</servlet-name>
    <servlet-class>com.example.xmpp.ChatServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>Chat</servlet-name>
    <url-pattern>/_ah/xmpp/message/chat/</url-pattern>
</servlet-mapping>
<!-- Handles the presence part of XMPP. -->
<servlet>
    <servlet-name>Presence</servlet-name>
    <servlet-class>com.example.xmpp.PresenceServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>Presence</servlet-name>
    <url-pattern>/_ah/xmpp/presence/*</url-pattern>
</servlet-mapping>  
<!-- Handles the subscription part of XMPP. -->
<servlet>
    <servlet-name>Subscribe</servlet-name>
    <servlet-class>com.example.xmpp.SubscribeServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>Subscribe</servlet-name>
    <url-pattern>/_ah/xmpp/subscription/*</url-pattern>
</servlet-mapping>

Retrieving URL Parameter Values With Pure Javascript

Here is a short but incredibly useful piece of Javascript: it retrieves the value of a named URL parameter. For example, if the current page’s address is index.html?example=true&name=vinny this function would return vinny if passed the name name , and it would return true if passed the name example .

function getParameterByName(name) {
    var match = RegExp('[?&]' + name + '=([^&]*)').exec(window.location.search);
    return match && decodeURIComponent(match[1].replace(/\+/g, ' '));
}

A note of warning: calling this method repeatedly is inefficient, since the regular expression needs to be repeated every time.

Sending A XMPP Message

Here’s a code sample demonstrating how to send a XMPP message using the App Engine XMPP service. The text of the message is contained in the string reply_body while the recipient is represented by a JID object named from_jid . Applications can retrieve the recipient’s JID by extracting it from a previous message, presence request, or subscribe request.

//Build a message to reply to the user.
MessageBuilder message_builder = new MessageBuilder();
message_builder.withRecipientJids(from_jid);
message_builder.withBody(reply_body);
Message reply_message = message_builder.build();
//Send the message back to the user.
SendResponse response_status = xmpp.sendMessage(reply_message);

Remember to import the XMPP package:

import com.google.appengine.api.xmpp.*;

Unable to find property ‘application’ on class: IndexYamlReader

A quick note for today: some developers are experiencing the below error while attempting to vacuum an application’s indexes:

Error Details:
Line 0, column 10: Unable to find property 'application' on class:
com.google.apphosting.utils.config.IndexYamlReader
.
com.google.appengine.tools.admin.AdminException: Unable to perform vacuum_indexes
    at com.google.appengine.tools.admin.AppAdminImpl.vacuumIndexes(AppAdminImpl.java:346)
    at com.google.appengine.tools.admin.AppCfg$VacuumIndexesAction.execute(AppCfg.java:1605)
    at com.google.appengine.tools.admin.AppCfg.executeAction(AppCfg.java:327)
    at com.google.appengine.tools.admin.AppCfg.<init>(AppCfg.java:210)
    at com.google.appengine.tools.admin.AppCfg.<init>(AppCfg.java:121)
    at com.google.appengine.tools.admin.AppCfg.main(AppCfg.java:117)

Google seems to have changed the index backend during the 1.8.6 App Engine release, and this is causing older SDK versions to break when they attempt to issue the vacuum indexes command. To fix this, update your SDK version to the latest available.

Cloud Integration: An Error Occurred When Creating The Project

While integrating an App Engine application into a Google Cloud project, you may experience the below error:

Here is the transcribed form:

Cloud Integration
Create a Google Cloud project for this application.
An error occurred when creating the project. Please retry.

While this error is rare, it can easily be fixed. Press the Retry button to try integrating the project again; this will solve the vast majority of failures. If this error occurs repeatedly, you may wish to file an issue on the tracker. There are some integration errors that are documented, such as issue 9602: https://issuetracker.google.com/issues/35895752  .

In the interim – until integration succeeds – App Engine applications can be configured to use assets and services that are technically within a separate project. For example, GAE applications can access Cloud Storage buckets that are listed in a separate project as long as their service account names are listed in the bucket ACLs.

Instances Processing Requests Unevenly

Sometimes instances on App Engine handle incoming requests very oddly. Here’s an example (this is a screenshot of the Instances page in the admin console):

As you can see, the first instance has processed over 40,000 requests within the last 2 hours 18 minutes. The second instance has only processed 7 requests, despite the fact that it has been running for over an hour. Notice also how the first instance has a much higher QPS and a slightly higher memory footprint compared to the second instance.

RetryOptions Example In Java

Here’s a demonstration of how to set the retry options on a task. The following code configures a task to retry 3 times (if the initial request fails) and to double the time between retries at most twice.

//Configures the retry options for the task. 
//Here we're saying to retry 3 times if the task initially 
//fails, and to increase the time between retries.
RetryOptions retry = RetryOptions.Builder.withTaskRetryLimit(3);
retry.maxDoublings(2);

The following line sets the options onto a task ( task represents a TaskOptions object ):

task.retryOptions(retry);

Remember to import the RetryOptions class:

import com.google.appengine.api.taskqueue.RetryOptions;

Extracting The Latest Video From YouTube’s Data API

Here’s a simple function demonstrating how to access the YouTube Data API. This code extracts the title and URL of the latest video uploaded by a given user, then records the information to logs.

The title and URL of the video are contained in the variables video_title and video_url . This code snippet pulls the latest video uploaded by the user TEDtalksDirector – this can be changed by editing the url variable.

/**
 * In this method, we'll pull the latest video uploaded 
 * from a specific user.
 * 
 * @throws IOException May be thrown by the low-level URLFetch service.
 */
public void getYouTubeVideo() {
    try {
        //This is the API url for videos uploaded by the user TEDtalksDirector
        URL url = new URL("http://gdata.youtube.com/feeds/api/users/TEDtalksDirector/uploads?prettyprint=true&v=2&alt=jsonc");
        //Have the URLFetch library grab the contents of the URL.
        HTTPResponse response = URLFetchServiceFactory.getURLFetchService().fetch(url);
        String response_contents = new String(response.getContent());
        //If the response was successful, process the returned JSON.
        //This line goes through the JSON tree to find and retrieve 
        //the JSON object representing the last uploaded video.
        JSONArray video_list = (new JSONObject(response_contents)).getJSONObject("data").getJSONArray("items");
        JSONObject latest_video = video_list.getJSONObject(0);
        //Pull out the video title and url.
        String video_title = latest_video.getString("title");
        String video_url = latest_video.getJSONObject("player").getString("default");
        System.out.println("Latest YouTube Video Title: " + video_title + " URL: " + video_url);
    }//end try 
    catch (IOException e) {
        System.err.println("IOException while retrieving YouTube data: " + e.getMessage());
    }
    catch (JSONException e) {
        System.err.println("JSONException while parsing YouTube response: " + e.getMessage());
    }
}//end getYouTubeVideo()

To use this code, you’ll need to add in the org.json library and import the following packages:

import java.net.URL;
import com.google.appengine.api.urlfetch.HTTPResponse;
import com.google.appengine.api.urlfetch.URLFetchServiceFactory;
import org.json.*;
import java.io.IOException;