Use Function Logging

Salesforce Functions provides logging to monitor, debug, and analyze how your deployed functions are running. Log information is captured at the compute environment level, which means that logged activity for all functions deployed to a given compute environment is captured in the same log, which can then be filtered by function, date/time, or other logline fields.

Compute environment log information is not persisted by Salesforce. If you need to persist log information you will need to set up a log drain to a system that can receive the log information and persist it.

Compute environment logs do not capture any log information generated from your Salesforce orgs. For example, any Apex logs created from your Apex code that invokes a function isn’t capture in compute environment logs. For dealing with log information from Apex code, see Working with Apex Debug Logs.

Generate Log Information in Your Function Code 

Functions are provided with a pre-initialized logging handler that can be used to capture application logs for the duration of the function execution. JavaScript function entry points will automatically receive the pre-initialized Logger instance that you can use to add log entries for debugging purposes, or general logging:

1export default async function execute(event, context, logger) {
2  // Make a data request
3  const results = await context.org.dataApi.query("SELECT Id, Name FROM Account");
4  // Log results
5  logger.info(JSON.stringify(results));
6}

Java functions should use the SLF4J logging framework for logging. The Java SDK for Functions provides a custom SLF4J logger binding that automatically adds function-specific info to loglines, such as the invocation ID.

You don’t need to add your own SLF4J binding such as log4j or logback. Instead, just use SLF4J’s LoggerFactory to get a Logger instance with the custom bindings. For more information on using SLF4J, see Frequently Asked Questions about SLF4J.

Here’s a Java function example that uses the SLF4J logging framework:

1import com.salesforce.functions.jvm.sdk.SalesforceFunction;
2import org.slf4j.Logger;
3import org.slf4j.LoggerFactory;
4
5import java.io.IOException;
6
7public class LoggingFunction implements SalesforceFunction<byte[], String> {
8    private final static Logger LOGGER = LoggerFactory.getLogger(LoggingFunction.class);
9
10    @Override
11    public String apply(InvocationEvent<byte[]> event, Context context) {
12        LOGGER.debug("Hello world from logger!");
13        ...
14    }
15}

View Compute Environment Logs 

To access the log for your compute environment, use the sf env log tail command, providing the compute environment where your function is deployed.

1sf env log tail -e MyComputeEnvironment

Log information will start to output to the current shell. To stop capturing logs, quit the process by using Ctrl-C in your shell. Logs are captured for all activity within the compute environment, so filter for just the functions you’re interested in, if needed.

Note that environment logs aren’t buffered, so this command starts capturing and outputting log lines that occur after the command is executed. If you want to capture log details during a function invocation you should start tailing the environment log in a separate shell before the function is invoked.

If no function is active in the environment, the log tailing stops after 1 hour of continued inactivity. To continue capturing logs for that environment, re-run the sf env log tail command.

After running sf env log tail and invoking a function, the output might look something like the following:

1sf env log tail -e Billing-Scratch1
22021-06-08T14:53:07.383016+00:00 app[api]: Release v4 created by user 00db0000000yqvymag_005b0000007n4s8iak@evergreeninternal.herokai.com
32021-06-08T14:53:56.080334+00:00 app[jsfunction-6f4759b448-m9bs2]: {"level":30,"time":1623164036079,"pid":1,"hostname":"jsfunction-6f4759b448-m9bs2","invocationId":"00D1g000000BRQwEAO-4cOjnHHmAJKaG9-qbxt19--0a2ef6d0","msg":"Invoking Jsfunction with payload {}"}
42021-06-08T14:53:56.292712+00:00 app[jsfunction-6f4759b448-m9bs2]: {"level":30,"time":1623164036292,"pid":1,"hostname":"jsfunction-6f4759b448-m9bs2","invocationId":"00D1g000000BRQwEAO-4cOjnHHmAJKaG9-qbxt19--0a2ef6d0","msg":"{\"done\":true,\"totalSize\":1,\"records\":[{\"type\":\"Account\",\"fields\":{\"id\":\"0011g00000uzeGdAAI\",\"name\":\"Sample Account for Entitlements\"}}]}"}
52021-06-08T14:56:42.000000+00:00 app[api]: Build started by user 00db0000000yqvymag_005b0000007n4s8iak@evergreeninternal.herokai.com
62021-06-08T14:57:35.000000+00:00 app[api]: Build succeeded
72021-06-08T14:57:35.750848+00:00 app[api]: Container build by user 00db0000000yqvymag_005b0000007n4s8iak@evergreeninternal.herokai.com
82021-06-08T14:57:35.750848+00:00 app[api]: Release v5 created by user 00db0000000yqvymag_005b0000007n4s8iak@evergreeninternal.herokai.com
92021-06-08T14:57:36.000000+00:00 app[api]: Build succeeded
102021-06-08T16:32:15.981869+00:00 app[jsfunction-844948ddcb-bd95b]: {"level":30,"time":1623169935981,"pid":1,"hostname":"jsfunction-844948ddcb-bd95b","invocationId":"00D1g000000BRQwEAO-4cPcS8zxQFB4ye-qbxt0S--2db15f58","msg":"Invoking Jsfunction with payload {}"}
112021-06-08T16:32:16.176039+00:00 app[jsfunction-844948ddcb-bd95b]: {"level":30,"time":1623169936175,"pid":1,"hostname":"jsfunction-844948ddcb-bd95b","invocationId":"00D1g000000BRQwEAO-4cPcS8zxQFB4ye-qbxt0S--2db15f58","msg":"{\"done\":true,\"totalSize\":1,\"records\":[{\"type\":\"Account\",\"fields\":{\"id\":\"0011g00000uzeGdAAI\",\"name\":\"Sample Account for Entitlements\"}}]}"}

Manage Log Drains 

You can also set up a log drain to capture logging information. Setting up a log drain lets you capture log output to an external system for archiving or analysis. As with log tailing, log information sent to log drains is captured at the compute environment level.

When you set up a log drain you need to provide a HTTP or HTTPS URL that can receive the log drain messages. Drain log messages are formatted based on the RFC5424 “syslog” format. They are delivered over TCP, using the octet counting framing method. HTTPS drains support transport-level encryption using the HTTPS protocol, and authentication using HTTP Basic Authentication.

Set a log drain for a compute environment using the sf env logdrain add CLI command, for example:

1sf env logdrain add -e MyComputeEnvironment -l syslog-receive.mylogservice.com:11137

You can set multiple log drain receivers if necessary.

To see what log drains are currently set for your compute environment, if any, use the sf env logdrain list command:

1sf env logdrain list -e MyComputeEnvironment

To remove a log drain, use the sf env logdrain remove command, providing both the compute environment and the log drain receiver URL:

1sf env logdrain remove -e MyComputeEnvironment -url syslog-receive.mylogservice.com:11137

Set up your function log drains to work with a third-party system or provide your own using a log service like log-iss. For convenience, we provide basic steps for setting up log drains for your functions with some of the more popular third-party systems. These examples don’t include all the systems that support log drains for your functions.

Coralogix

  1. Create an account in Coralogix if you don’t already have one.
  2. Get your account’s private-key and company ID by going to Settings > Send Your Logs. Choose an application-name to be associated with the logs.
  3. Use the sf env logdrain add command as described earlier, with a URL with the following format:
1https://(redacted)@api.coralogix.com/logs/heroku/private?appName=

LogDNA

  1. Create an account on www.logdna.com if you don’t already have one.
  2. Open the LogDNA webapp and click All Hosts > Add a host.
  3. Navigate to the Heroku section and execute the account-specific commands found under the Installing via Heroku Log Drains section.
  4. Use the log drain URL in your sf env logdrain add command as described above.

Papertrail

  1. If you don’t already have a Papertrail account, sign up for one at https://www.papertrail.com/plans/.
  2. Sign into your account and click on Add Systems
  3. Select aggregating “app log files” from “Heroku”. For choosing a method, choose “Method 2: Standalone”.
  4. Under “Setup Heroku drain” Papertrail will provide a Heroku CLI command that will include the log drain URL, for example:
1heroku drains:add syslog+tls://logs6.papertrailapp.com:20257

Use this URL in your sf env logdrain add command as described earlier. With the above Heroku CLI command example, your sf env logdrain add command would look like:

1sf env logdrain add --environment=MyComputeEnvironment --url=syslog+tls://logs6.papertrailapp.com:20257

Splunk

  1. Install the RFC5424 Syslog add-on in your Splunk Enterprise platform.
  2. Create a new HTTP Event Collector token. Follow the Splunk documentation. For “name”, use a unique identifier for your compute environment. For “source type” use “rfc5424_syslog”.
  3. Generate a random channel UUID. This is required to for raw event collection by Splunk.
  4. Construct your log drain URL with the token and channel created in the steps above:
1https://x:TOKEN@yoursplunkhost.example.com:yourport/services/collector/raw?channel=CHANNEL_UUID

For example:

1https://x:1234ABCD-C66E-4B22-854F-5958C7FA637D@yoursplunkhost.domain.com:yourport/services/collector/raw?channel=12341238-adbd-abcd-9dbe-16629695fb1d
  1. Use this log drain URL in your sf env logdrain add command as described earlier.

Sumo Logic

  1. Configure a Sumo Logic Hosted Collector with an HTTP Source.
  2. Use the URL associated with the HTTP source that Sumo Logic provides in your sf env logdrain add command as described earlier.

Work with Apex Debug Logs 

When invoking your function using Apex, you can use Apex debug logs to get information on how the function was invoked. You can view Apex debug logs from within the org (through the Developer Console or the Debug Logs Setup page). From the CLI, use the sf apex list log and sf apex get log to obtain debug logs for your function invocation. For example, if you invoked a function asynchronously, you could use sf apex list log to get a list of recent logs:

1$ sf apex list log
2APPLICATION  DURATION (MS)  ID                  LOCATION   SIZE (B)  LOG USER   OPERATION                REQUEST      START TIME                STATUS
3───────────  ─────────────  ──────────────────  ─────────  ────────  ─────────  ───────────────────────  ───────────  ────────────────────────  ───────
4Unknown      2018323003     07L2F00000Hr3fgUAB  SystemLog  2190      User User  FunctionCallbackHandler  Application  2020-09-30T23:41:54+0000  Success
5Unknown      94             07L2F00000Hr3fbUAB  SystemLog  4554      User User  Api                      Api          2020-09-30T23:41:54+0000  Success

Using the sf apex get log command with the ID from the FunctionCallbackHandler operation, you can get more Apex log details on what happened when your async function was invoked.

If you’re working with a new scratch org and you can’t see debug logs (sf apex list log returns “No debug logs found in org”), open the Developer Console (once) in that org. Opening the Developer Console creates a Traceflag record that enables Apex debug logging.

When invoking functions asynchronously using Apex, you may not be able to see Apex logs for the Apex callback. This is because the callback is being run as the Platform Integration user, which might not have Apex debugging enabled. To enable debugging for the Platform Integration user, in your org, from Setup, search for “Debug Logs”. Create a User Trace Flag and specify “Platform Integration” as the Trace Entity Type.

For more information on using Apex debug logs, see Apex Developer Guide: Debug Log

Product Retirement Announcement

Salesforce Functions is no longer available for purchase or renewal. To preserve the capabilities that Salesforce Functions provided to your org, deploy an alternative solution before your existing order term ends. See Salesforce Functions Retirement for more information on migrating your functions. Contact your Salesforce Account Executive for more information on Heroku.