Retrieve session data via Inquire Rest API

Inquire Rest API allows you to obtain detailed session data for each session stored in the Log Data Source (LDS). The following code can help you extract session data and save it as a JSON or as a JSON Lines file. It can help you in the following aspects:

  • Save historical session data. This can be helpful to keep track of data which gets removed from the LDS due to the established retention time.
  • Use other methods than Teneo Query Language (TQL) to analyze your data. With JSON or JSON Lines file you can analyze data using any language that you are most comfortable with, such as Python, R, etc.

Please copy the following Groovy code and save it as ExtractSessionData.groovy or similar names you prefer.

import java.net.http.HttpClient
import java.net.http.HttpRequest
import java.net.http.HttpResponse
import groovy.json.JsonBuilder
import groovy.json.JsonSlurper

class InquireApi {

	// Define properties
	private static String baseUrl = "" 
	private static String username = "" 
	private static String password = "" 
	private static String lds = "" 
	private static String accessToken = ""
	
	// Initialization
	InquireApi(String baseUrl, String username, String password, String lds){
		this.baseUrl = baseUrl
		this.username = username
		this.password = password
		this.lds = lds
	}

	// Log in Teneo Inquire engine
	public static void login() {

		def apiUrl = this.baseUrl + "teneo-inquire/rest/auth/login"
		HttpRequest request = HttpRequest.newBuilder()
			.uri(URI.create(apiUrl))
			.header("Content-type", "application/json")
			.method("POST", HttpRequest.BodyPublishers.ofString(new JsonBuilder(["user":this.username,"pass":this.password]).toString()))
			.build()

		HttpResponse<String> response = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString())
		if (response.statusCode() == 200) {
			println("Log in successfully.")
			this.accessToken = response.body()
		} else {
			throw new Exception("Error in login, error code: " + response.statusCode()) 
		}		

	}
	
	// Log out from Teneo Inquire engine
	public static void logout() {

		def apiUrl = this.baseUrl + "teneo-inquire/rest/auth/logout"
		HttpRequest request = HttpRequest.newBuilder()
			.uri(URI.create(apiUrl))
			.header("Content-type", "application/json")
			.header("Authorization", "Bearer "+accessToken)
			.method("POST", HttpRequest.BodyPublishers.noBody())
			.build()

		HttpResponse<String> response = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString())
		if (response.statusCode() == 200) {
			println("Log out successfully.")
		} else {
			throw new Exception("Error in log out, error code: " + response.statusCode()) 
		}	

	}
	
	// Run a query via Inquire API (return query ID)
	public static String runQuery(String query, int maxResults) {

		def apiUrl = this.baseUrl + "teneo-inquire/rest/tql/submit?lds=" + this.lds + "&esPageSize=" + maxResults
		HttpRequest request = HttpRequest.newBuilder()
			.uri(URI.create(apiUrl))
			.header("Content-type", "application/x-www-form-urlencoded")
			.header("Authorization", "Bearer "+accessToken)
			.method("POST", HttpRequest.BodyPublishers.ofString("query="+URLEncoder.encode(query)))
			.build()

		HttpResponse<String> response = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString())
		if (response.statusCode() == 200) {
			def result = new JsonSlurper().parseText(response.body())
			return result.id
		} else {
			throw new Exception("Error in running query, error code: " + response.statusCode()) 
		}	

	}
	
	// Get query result by query ID
	public static List getQueryResult(String queryId) {

		def apiUrl = this.baseUrl + "teneo-inquire/rest/tql/poll?id=" + queryId
		HttpRequest request = HttpRequest.newBuilder()
			.uri(URI.create(apiUrl))
			.header("Authorization", "Bearer "+accessToken)
			.method("GET", HttpRequest.BodyPublishers.noBody())
			.build()

		HttpResponse<String> response = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString())
		if (response.statusCode() == 200) {
			def result = new JsonSlurper().parseText(response.body())
			return result.result
		} else {
			throw new Exception("Error in getting query result, error code: " + response.statusCode()) 
		}	

	}
	
	// Get session data from session ID
	public static Map getSessionData(List<String> sessionIds) {

		def apiUrl = this.baseUrl + "teneo-inquire/rest/data/" + this.lds + "/session?id=" + sessionIds.join("&id=")
		HttpRequest request = HttpRequest.newBuilder()
			.uri(URI.create(apiUrl))
			.header("Authorization", "Bearer "+accessToken)
			.method("GET", HttpRequest.BodyPublishers.noBody())
			.build()

		HttpResponse<String> response = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString())
		if (response.statusCode() == 200) {
			def result = new JsonSlurper().parseText(response.body())
			return result
		} else {
			throw new Exception("Error in getting session data, error code: " + response.statusCode()) 
		}	

	}
	
}

// Convert session id list to batches
public static List<String> toBatch(List<String> inputList, int batchSize){
	
	def batchedList = []
	for (int i = 0; i < inputList.size(); i+=batchSize){
		batchedList << inputList.subList(i,Math.min(inputList.size(),i+batchSize))
	}
	return batchedList
	
}

public static void main(String[] args) {

	def endpoint = '' // Fill in your endpoint url (begin with "http://query.")
	def username = '' // Fill in your username (the same username you use for Teneo Studio)
	def password = '' // Fill in your password (the same password you use for Teneo Studio)
	def lds = '' // Fill in the LDS name
	def outputFormat = "json" // By default we use standard JSON file. You can change it to "jsonl" if you need a json lines file
	def query = 'la s.id as sid order by s.beginTime asc' // This is a query to retrieve the list of session IDs ordered by begin time of the session. You can add time restrictions such as 's.beginTime == in {"now-1w/w"}' (extract all data logged during the last calendar week)
	def maxResults = 10000 // Maximum of results allowed for single query. Please make sure the number of session you need to extract is lower than the maximum number of results allowed.
	def batchSize = 100 // The batch size of session ids to be sent to the method getSessionData. In most of the cases you do not need to change it. If you see error caused by the size of request like error 414 or 431, please choose a smaller batch size.
	
	// Get output file name from the argument or use default file name
	def fileName = ''
	if(args){
		fileName = args[0]
		if (fileName.endsWith("jsonl")) outputFormat = "jsonl"
		else if (fileName.endsWith("json")) outputFormat = "json"
	}
	else{
		fileName = "SessionData." + outputFormat
	}
	// Check the extension of the output file
	fileName = fileName.endsWith(outputFormat)?fileName:fileName + "." + outputFormat
	
	// Create Inquire API connector instance
	def inquireConnector = new InquireApi(endpoint,username,password,lds)
	
	// Log in Inquire engine
	inquireConnector.login()
	
	// Run the query and retrieve the list of session IDs
	def queryId = inquireConnector.runQuery(query,maxResults)
	def results = inquireConnector.getQueryResult(queryId)
	
	// Generate batched session ids 
	def batchedSessionIds = toBatch(results.sid,batchSize)
	
	// Retrieve session data according to the session IDs
	def sessionDatas = []
	println("Starting retrieving session data. " + results.size() + " sessions in total.")
	for (int i=0; i<batchedSessionIds.size(); i++){
		
		for (sessionData in inquireConnector.getSessionData(batchedSessionIds[i])){
			sessionDatas << sessionData		
		}
		// Print progress every batch
		println(Math.min((i+1)*batchSize,results.size()) + " sessions have been processed.")
			
	}

	// Write the output file
	BufferedWriter writer = new BufferedWriter(new FileWriter(fileName))
	if (outputFormat == "json") {
		writer.write(new JsonBuilder(sessionDatas).toString())
	} else {
		for (sessionData in sessionDatas){
			writer.write(new JsonBuilder(sessionData).toString())
			writer.write("\n")
		}
	}
	writer.close()
	
	println(outputFormat + " file written successfully: " + fileName)
	
	// Log out from Inquire engine
	inquireConnector.logout()

}

Before you run the code, you need to fill in the following information in the main function (obligatory):

  • endpoint: The Inquire backend of your solution. You can find it by opening the Studio and clicking on the About button on the left, copy the URL from Connected to, and replace studio with query in the URL.
  • username: The same username you use to log in the Teneo Studio
  • password: The same password you use to log in the Teneo Studio
  • lds : The name of the Log Data Source

And adjust the following variables if needed (optional):

  • outputFormat: The output format, should be json (by default) or jsonl. It will be automatically adjusted if you indicate the output file name in the argument.
  • query: The query used to extract all session IDs. By default, it doesn’t contain any restriction so it will extract ALL sessions in LDS order by session begin time. You can add a time period or other restrictions to it following TQL syntax.
  • maxResults: The maximum number of results, by default set to 10000. Please only change it if you plan to extract data of more than 10000 sessions.
  • batchSize: By default, we send an API request with 100 session IDs at one time in order to save time and lower the frequency of API calls. Please do not increase the batch size. If you get an error related to request or header length such as error 414 or 431, please reduce the batch size and try again.

Then run the following command in the Command Prompt in your operating system (with Groovy installed in advance):

groovy ExtractSessionData.groovy yourOutputFile.json

You can omit the argument for file name. In this case, a file named SessionData.json or SessionData.jsonl (depends on the variable outputFormat) will be created in the current folder path.

2 Likes

for Inquire Rest API version 7.2.0, please use the following requst body instead:

["username":this.username,"password":this.password]