A) via ToolingAPI
I'm trying to execute apex-code via
public ExecuteAnonymousResult executeAnonymousEncoded(String body)
of the ToolingAPI.cls from within APEX. So far it works. But I was not able to receive a proper debug log. Neither error-messages show up. I need the logs as a string to output them back to users. Somehow the Log-Level has to be set in the Header to get logs, but I was not able to do so using ToolingAPI.cls – any idea?
B) via SoapAPI
As an alternative, I tried to make a callout to the SoapAPI, which also fails.
Wanted to call that function http://www.salesforce.com/us/developer/docs/apexcode/index_Left.htm#CSHID=sforce_api_calls_executeanonymous.htm|StartTopic=Content%2Fsforce_api_calls_executeanonymous.htm|SkinName=webhelp
But this way I found how to set the header. Here the code I used:
public with sharing class callout {
public static string exec() {
Http h = new Http();
HttpRequest req = new HttpRequest();
URL baseUrl = URL.getSalesforceBaseUrl();
req.setEndpoint( baseUrl.toExternalForm() + '/services/Soap/m/'+'29.0');
req.setMethod('POST');
req.setHeader('Content-Type', 'text/xml');
req.setHeader('SOAPAction', '""');
req.setBody(''
+'<?xml version="1.0" encoding="UTF-8"?>'
+'<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:apex="urn:partner.soap.sforce.com" >'
+'<soapenv:Header>'
+'<apex:DebuggingHeader>'
+'<apex:debugLevel>Detail</apex:debugLevel>'
+'</apex:DebuggingHeader>'
+'<apex:SessionHeader>'
+'<apex:sessionId>'+UserInfo.getSessionId()+'</apex:sessionId>'
+'</apex:SessionHeader>'
+'</soapenv:Header>'
+'<soapenv:Body>'
+'<apex:executeAnonymous>'
+'<apex:String>'
+'Account a = new Account(Name=\'Test Account\', phone=\'111222111\');'
+'insert a;'
+'System.debug(\'New Account Name \' + a.Name);'
+'</apex:String>'
+'</apex:executeAnonymous>'
+'</soapenv:Body>'
+'</soapenv:Envelope>'
);
HttpResponse res = h.send(req);
return res.getBody();
}
}
I got only:
<?xml version=\"1.0\" encoding=\"UTF-8\"?>
<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\">
<soapenv:Body>
<soapenv:Fault>
<faultcode>soapenv:Client</faultcode>
<faultstring>No operation available for request {urn:partner.soap.sforce.com}executeAnonymous</faultstring></soapenv:Fault>
</soapenv:Body>
</soapenv:Envelope>
C) via Javascript AJAX-Toolkit – Temporary Solution (very bad)
I temporarily solved it using a very hackish approach via the AJAX-Toolkit using javascript…. it works but I need to deeply hack into salesforce javascript to reroute the debug-output and a need a sessionId from
- https://XXX.salesforce.com/ instead of
- https://elfcodefusion.XXX.visual.force.com (where XXX is your pod)
this specific SessionId is actually very hard to get after salesforce enabled clickjack-protection for non-setup-pages by default. If one is interested on how I did, let me know, I provide details. But it is ugly – as I said. But at least it works, and its very fast but will never pass a security review! 😉
Now, I want to get rid of that mess and do it the "right way"
Best Answer
I imported the Tooling API WSDL back into Apex as
toolingSoapSforceCom
and added a Remote Site setting from my Salesforce pod/domain.I could then call the Tooling API with:
When doing similar calls the the Apex WSDL I would then retrieve the resulting Apex Log from the DebuggingInfo header. It would appear that the DebuggingInfo header either isn't coming back from the call or isn't being populated by wsdl2apex.
My second attempt was to use a direct Http request using the XML body generated by the above attempt.
Using HttpResonse.getHeaderKeys() I went looking for the DebuggingInfo SoapHeader in the response. It didn't appear to be there.
I could however query the ApexLog via SOQL and see new records being created that contained the logs.
Attempt # 3 was to using the Apex web service rather than the tooling API. Again, I imported the WSDL using wsdl2apex.
This was partially successful. The CALLOUT_RESPONSE did have a
<soapenv:Header><DebuggingInfo><debugLog>
in the response. However, this wasn't populated into the DebuggingInfo property in Apex. However, you could copy the XML from the CALLOUT_REQUEST and send it via HttpRequest to https://na5.salesforce.com/services/Soap/s/30.0 so you can parse the log out of the response.The CALLOUT_REQUEST XML: