A contextual query locates logs immediately before and after a target log from a specific source. When you process large volumes of logs, assign a PackId to group related logs for fast, complete context retrieval.
How it works
A PackId follows the format contextual prefix-log group ID, for example, 5FA51423DDB54FDA-1E3:
-
contextual prefix: Uppercase hexadecimal digits, such as
5FA51423DDB54FDA. Logs that share a contextual prefix belong to the same log context. -
log group ID: Uppercase hexadecimal digits, such as
1E3. Within a log context, thelog group IDincrements sequentially. For example,1E3and1E4are adjacent groups.
The client generates a PackId and sends it with the log write request. Simple Log Service groups logs that share a contextual prefix into the same log context.
Automatically generate PackId
-
Logs written by using a producer SDK: Logs from the same producer instance share a context and support contextual queries. The Aliyun Log Java Producer and the C Producer SDK automatically generate and attach a PackId.
-
Logs collected by Logtail: Logtail automatically generates and attaches a PackId. Logs from the same file on the same host or pod share a context and support contextual queries.
Manually generate PackId with the PutLogs API
Parameters
When you call the PutLogs API, include the PackId in the LogTags attribute of the LogGroup in your PutLogs request. Set the Key to __pack_id__:
{
"Topic": "my-topic",
"Source": "127.0.0.1",
"LogTags": [
{
"Key": "__pack_id__",
"Value": "5FA51423DDB54FDA-1"
},
{
"Key": "my_other_tag_key",
"Value": "my_other_tag_value"
}
],
"Logs": [
{
"Time": 1728961415,
"Contents": [
{
"Key": "hello",
"Value": "world"
}
]
}
]
}
Sample code
Java example
-
Add the following dependencies to the pom.xml file.
<dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>27.0.1-jre</version> </dependency> <dependency> <groupId>com.aliyun.openservices</groupId> <artifactId>aliyun-log</artifactId> <version>0.6.111</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>2.0.12</version> </dependency> -
Run the following code to generate a PackId and upload it through PutLogs. Replace
project,logstore,endpoint,accessKeyId, andaccessKeySecretwith your actual values.package org.example; import com.aliyun.openservices.log.Client; import com.aliyun.openservices.log.common.LogItem; import com.aliyun.openservices.log.common.TagContent; import com.aliyun.openservices.log.exception.LogException; import com.aliyun.openservices.log.request.PutLogsRequest; import com.google.common.base.Charsets; import com.google.common.hash.Hashing; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.lang.management.ManagementFactory; import java.net.InetAddress; import java.net.NetworkInterface; import java.net.SocketException; import java.util.ArrayList; import java.util.Arrays; import java.util.Enumeration; import java.util.List; import java.util.concurrent.atomic.AtomicLong; public class Main { private static final String TAG_PACK_ID = "__pack_id__"; private static final int TOKEN_LEN = 4; public static void main(String[] args) throws LogException { System.out.println("Hello world!"); // Use the same PackIdGenerator instance for the same context. PackIdGenerator generator1 = new PackIdGenerator(); System.out.println(generator1.generateNewPackId()); System.out.println(generator1.generateNewPackId()); System.out.println(generator1.generateNewPackId()); // Use different PackIdGenerator instances for different contexts. PackIdGenerator generator2 = new PackIdGenerator(); System.out.println(generator2.generateNewPackId()); System.out.println(generator2.generateNewPackId()); // Configure log parameters. String project = "your-project-name"; String logstore = "your-logstore-name"; String topic = "your-topic"; String source = "127.0.0.1"; Client client = new Client("your-endpoint", "your-access-key-id", "your-access-key-secret"); List<LogItem> logs = new ArrayList<>(); LogItem log = new LogItem(); log.PushBack("hello", "world"); logs.add(log); // Send a log request. PutLogsRequest req = new PutLogsRequest(project, logstore, topic, source, logs); // Add the PackId to the tag list. req.SetTags(Arrays.asList(new TagContent(TAG_PACK_ID, generator1.generateNewPackId()))); client.PutLogs(req); // Send another log request. PutLogsRequest req2 = new PutLogsRequest(project, logstore, topic, source, logs); req.SetTags(Arrays.asList(new TagContent(TAG_PACK_ID, generator1.generateNewPackId()))); client.PutLogs(req2); } public static class NetworkUtils { private NetworkUtils() { } public static boolean isIpAddress(final String ipAddress) { if (ipAddress == null || ipAddress.isEmpty()) { return false; } try { final String[] tokens = ipAddress.split("\\."); if (tokens.length != TOKEN_LEN) { return false; } for (String token : tokens) { int i = Integer.parseInt(token); if (i < 0 || i > 255) { return false; } } return true; } catch (Exception ex) { return false; } } public static String getLocalMachineIp() { try { Enumeration<NetworkInterface> networkInterfaces = NetworkInterface.getNetworkInterfaces(); while (networkInterfaces.hasMoreElements()) { NetworkInterface ni = networkInterfaces.nextElement(); if (!ni.isUp()) { continue; } Enumeration<InetAddress> addresses = ni.getInetAddresses(); while (addresses.hasMoreElements()) { final InetAddress address = addresses.nextElement(); if (!address.isLinkLocalAddress() && address.getHostAddress() != null) { String ipAddress = address.getHostAddress(); if ("127.0.0.1".equals(ipAddress)) { continue; } if (isIpAddress(ipAddress)) { return ipAddress; } } } } } catch (SocketException ex) { // Ignore the exception. } return null; } } public static class PackIdGenerator { private static final Logger LOGGER = LoggerFactory.getLogger(PackIdGenerator.class); private static final AtomicLong GENERATORID = new AtomicLong(0); private final String packIdPrefix; private final AtomicLong batchId = new AtomicLong(0); public PackIdGenerator() { packIdPrefix = generatePackIdPrefix(GENERATORID.getAndIncrement()).toUpperCase() + "-"; } public String generateNewPackId() { return packIdPrefix + Long.toHexString(batchId.getAndIncrement()).toUpperCase(); } private String generatePackIdPrefix(Long instanceId) { String ip = NetworkUtils.getLocalMachineIp(); if (ip == null) { LOGGER.warn("Failed to get local machine ip, set ip to 127.0.0.1"); ip = "127.0.0.1"; } String name = ManagementFactory.getRuntimeMXBean().getName(); String input = ip + "-" + name + "-" + instanceId; return Hashing.farmHashFingerprint64().hashString(input, Charsets.US_ASCII).toString(); } } }
Go example
-
Install the Go SDK and the protobuf dependency.
go get -u github.com/aliyun/aliyun-log-go-sdk go get google.golang.org/protobuf -
Run the following code to generate a PackId and upload it through PutLogs. Replace
project,logstore,endpoint,accessKeyId, andaccessKeySecretwith your actual values.package main import ( "crypto/md5" "fmt" "os" "sync/atomic" "time" sls "github.com/aliyun/aliyun-log-go-sdk" "google.golang.org/protobuf/proto" ) func main() { // Use the same PackIdGenerator instance for the same context. g1 := NewPackIdGenerator() fmt.Println(g1.Generate()) fmt.Println(g1.Generate()) fmt.Println(g1.Generate()) // Use different PackIdGenerator instances for different contexts. g2 := NewPackIdGenerator() fmt.Println(g2.Generate()) fmt.Println(g2.Generate()) // Configure log parameters. project := "your-project-name" logstore := "your-logstore-name" topic := "your-topic" source := "your-source" client := sls.CreateNormalInterface("your-endpoint", "your-access-key-id", "your-access-key-secret", "") logs := []*sls.Log{ { Time: proto.Uint32(uint32(time.Now().Unix())), Contents: []*sls.LogContent{ { Key: proto.String("hello"), Value: proto.String("world"), }, { Key: proto.String("hi"), Value: proto.String("world"), }, }, }, } // Use the PostLogStoreLogsV2 operation to write logs. err := client.PostLogStoreLogsV2(project, logstore, &sls.PostLogStoreLogsRequest{ LogGroup: &sls.LogGroup{ Topic: &topic, Source: &source, Logs: logs, LogTags: []*sls.LogTag{ { Key: proto.String("__pack_id__"), // Add the PackId to the tag list. Value: proto.String(g1.Generate()), }, }, }, }) if err != nil { panic(err) } // Use the PutLogs operation to write logs. g1.Generate() creates a new PackId. err = client.PutLogs(project, logstore, &sls.LogGroup{ Topic: &topic, Source: &source, Logs: logs, LogTags: []*sls.LogTag{ { Key: proto.String("__pack_id__"), // Add the PackId to the tag list. Value: proto.String(g1.Generate()), }, }, }) if err != nil { panic(err) } } type PackIdGenerator struct { prefix string id atomic.Uint64 } func NewPackIdGenerator() *PackIdGenerator { return &PackIdGenerator{ prefix: generatePackIDPrefix(), id: atomic.Uint64{}, } } func (g *PackIdGenerator) Generate() string { return fmt.Sprintf("%s-%X", g.prefix, g.id.Add(1)) } // Generate context from the hostname, PID, and time. func generatePackIDPrefix() string { m := md5.New() m.Write([]byte(time.Now().String())) hostName, _ := os.Hostname() m.Write([]byte(hostName)) m.Write([]byte(fmt.Sprintf("%v", os.Getpid()))) return fmt.Sprintf("%X", m.Sum(nil)) }
View log context
-
In your project, click the target logstore. On the tab, find the target log and click the
icon.NoteLogs submitted through PutLogs with the same PackId contextual prefix are grouped into the same log context. Click context view to display log groups that share a contextual prefix, with the target log highlighted.
Set a time range, such as 15 minutes, and click query / analyze.
-
Scroll the page to view the context of the selected log.
In the context view panel, the current log is highlighted. Use older and newer to browse adjacent logs. Select a field from all fields or enter a keyword to highlight matches.
References
-
View log context in the console: Contextual query.
-
Write logs through an SDK or API: Use Aliyun Log Java Producer to write log data, C Producer SDK, PutLogs.