All Products
Search
Document Center

Simple Log Service:Use an SDK to collect metrics

Last Updated:Nov 29, 2024

Simple Log Service allows you to collect metrics by using an SDK. This topic provides examples on how to use Simple Log Service SDKs for Java, Go, and Python to collect metrics.

Note
  • The metrics that you want to collect must be in the format that is defined in Metric format.

  • We recommend that you use a Producer library to transfer data whenever possible. The Producer libraries for Java, Go, and C are provided. If you use other programming languages, multiple data records are put into a log group and transferred. This reduces network requests.

  • You can specify a value in one of the following units for the __time_nano__ field: seconds, milliseconds, microseconds, or nanoseconds.

  • In this topic, environment variables are configured to specify AccessKey pairs. For more information, see Configure environment variables.

Use Simple Log Service SDK for Java to collect metrics

For more information, see Install Aliyun Log Java Producer.

import com.aliyun.openservices.aliyun.log.producer.Callback;
import com.aliyun.openservices.aliyun.log.producer.LogProducer;
import com.aliyun.openservices.aliyun.log.producer.Producer;
import com.aliyun.openservices.aliyun.log.producer.ProducerConfig;
import com.aliyun.openservices.aliyun.log.producer.ProjectConfig;
import com.aliyun.openservices.aliyun.log.producer.Result;
import com.aliyun.openservices.aliyun.log.producer.errors.ProducerException;
import com.aliyun.openservices.log.common.LogItem;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import java.util.TreeMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;

public class Main {
    private static final Logger LOGGER = LoggerFactory.getLogger(Main.class);
    private static final Random random = new Random();

    public static void main(String[] args) throws InterruptedException {
        final String project = "";
        final String logstore = "";
        // The Simple Log Service endpoint. In this example, the Simple Log Service endpoint for the China (Hangzhou) region is used. Replace the parameter value with the actual endpoint. 
        final String endpoint = "https://cn-hangzhou.log.aliyuncs.com";
        // Configure environment variables. In this example, the AccessKey ID and AccessKey secret are obtained from environment variables. 
        final String accessKeyId = System.getenv("ALIBABA_CLOUD_ACCESS_KEY_ID");
        final String accessKeySecret = System.getenv("ALIBABA_CLOUD_ACCESS_KEY_SECRET");
        int sendThreadCount = 8;
        final int times = 10;
        LOGGER.info(
                "project={}, logstore={}, endpoint={}, sendThreadCount={}, times={}",
                project, logstore, endpoint, sendThreadCount, times);
        ExecutorService executorService = Executors.newFixedThreadPool(sendThreadCount);
        ProducerConfig producerConfig = new ProducerConfig();
        producerConfig.setBatchSizeThresholdInBytes(3 * 1024 * 1024);
        producerConfig.setBatchCountThreshold(40960);

        final Producer producer = new LogProducer(producerConfig);
        producer.putProjectConfig(new ProjectConfig(project, endpoint, accessKeyId, accessKeySecret));

        final AtomicInteger completedCount = new AtomicInteger(0);
        LOGGER.info("Test started.");
        long t1 = System.currentTimeMillis();
        final Map<String, String> labels = new HashMap<String, String>();
        labels.put("test_k", "test_v");
        for (int i = 0; i < sendThreadCount; ++i) {
            executorService.submit(
                    new Runnable() {
                        @Override
                        public void run() {
                            try {
                                for (int i = 0; i < times; ++i) {
                                    int r = random.nextInt(times);
                                    producer.send(project, logstore, generateTopic(r), generateSource(r),
                                            buildLogItem("test_metric", labels, i),
                                            new Callback() {
                                                @Override
                                                public void onCompletion(Result result) {
                                                    completedCount.incrementAndGet();
                                                    if (!result.isSuccessful()) {
                                                        LOGGER.error(
                                                                "Failed to send log, project={}, logstore={}, result={}",
                                                                project,
                                                                logstore,
                                                                result);
                                                    }
                                                }
                                            });
                                }
                            } catch (Exception e) {
                                LOGGER.error("Failed to send log, e=", e);
                            }
                        }
                    });
        }
        while (completedCount.get() < sendThreadCount * times) {
            Thread.sleep(100);
        }
        long t2 = System.currentTimeMillis();
        LOGGER.info("Test end.");
        LOGGER.info("======Summary======");
        LOGGER.info("Total count " + sendThreadCount * times + ".");
        long timeCost = t2 - t1;
        LOGGER.info("Time cost " + timeCost + " millis");
        try {
            producer.close();
        } catch (ProducerException e) {
            LOGGER.error("Failed to close producer, e=", e);
        }
        executorService.shutdown();
    }

    private static String generateTopic(int r) {
        return "topic-" + r % 5;
    }

    private static String generateSource(int r) {
        return "source-" + r % 10;
    }

    /**
     * @param metricName: the metric name, eg: http_requests_count
     * @param labels:     labels map, eg: {'idc': 'idc1', 'ip': '192.0.2.0', 'hostname': 'appserver1'}
     * @param value:      double value, eg: 1.234
     * @return LogItem
     */
    public static LogItem buildLogItem(String metricName, Map<String, String> labels, double value) {
        String labelsKey = "__labels__";
        String timeKey = "__time_nano__";
        String valueKey = "__value__";
        String nameKey = "__name__";
        LogItem logItem = new LogItem();
        int timeInSec = (int) (System.currentTimeMillis() / 1000);
        logItem.SetTime(timeInSec);
        logItem.PushBack(timeKey, timeInSec + "000000");
        logItem.PushBack(nameKey, metricName);
        logItem.PushBack(valueKey, String.valueOf(value));

        // Sort labels in lexicographic order. If the labels are sorted, skip this step. 
        TreeMap<String, String> sortedLabels = new TreeMap<String, String>(labels);
        StringBuilder labelsBuilder = new StringBuilder();

        boolean hasPrev = false;
        for (Map.Entry<String, String> entry : sortedLabels.entrySet()) {
            if (hasPrev) {
                labelsBuilder.append("|");
            }
            hasPrev = true;
            labelsBuilder.append(entry.getKey());
            labelsBuilder.append("#$#");
            labelsBuilder.append(entry.getValue());
        }
        logItem.PushBack(labelsKey, labelsBuilder.toString());
        return logItem;
    }
}
            

Use Simple Log Service SDK for Python to collect metrics

For more information, see Install Simple Log Service SDK for Python.

# encoding: utf-8
import time
import os
from aliyun.log import *

def build_log_item(metric_name, labels, value):
    """
    build log item
    :param metric_name: the metric name, eg: http_requests_count
    :param labels: dict labels, eg: {'idc': 'idc1', 'ip': '192.0.2.0', 'hostname': 'appserver1'}
    :param value: double value, eg: 1.234
    :return: LogItem
    """
    sorted_labels = sorted(labels.items())
    log_item = LogItem()
    now = int(time.time())
    log_item.set_time(now)
    contents = [('__time_nano__', str(now)), ('__name__', metric_name), ('__value__', str(value))]

    labels_str = ''
    for i, kv in enumerate(sorted_labels):
        labels_str += kv[0]
        labels_str += '#$#'
        labels_str += kv[1]
        if i < len(sorted_labels) - 1:
            labels_str += '|'

    contents.append(('__labels__', labels_str))
    log_item.set_contents(contents)
    return log_item

def main():
    # The Simple Log Service endpoint. In this example, the Simple Log Service endpoint for the China (Hangzhou) region is used. Replace the parameter value with the actual endpoint. 
    endpoint = 'cn-hangzhou.log.aliyuncs.com'
    # Configure environment variables. In this example, the AccessKey ID and AccessKey secret are obtained from environment variables. 
    accessKeyId = os.environ.get('ALIBABA_CLOUD_ACCESS_KEY_ID', '')
    accessKey = os.environ.get('ALIBABA_CLOUD_ACCESS_KEY_SECRET', '')
    project = ''
    logstore = ''

    client = LogClient(endpoint, accessKeyId, accessKey)
    item1 = build_log_item('test1', {'k1': 'v1'}, 1)
    item2 = build_log_item('test2', {'k2': 'v2'}, 2)
    item3 = build_log_item('test3', {'k3': 'v3'}, 3)
    items = [item1, item2, item3]
    res = client.put_logs(PutLogsRequest(project=project, logstore=logstore, logitems=items))
    res.log_print()

if __name__ == '__main__':
    main()

Use Simple Log Service SDK for Go to collect metrics

For more information, see Install Simple Log Service SDK for Go.

package main

import (
   "fmt"
   sls "github.com/aliyun/aliyun-log-go-sdk"
   "github.com/aliyun/aliyun-log-go-sdk/producer"
   "github.com/golang/protobuf/proto"
   "os"
   "os/signal"
   "sort"
   "strconv"
   "sync"
   "time"
)

func buildLogItem(metricName string, labels map[string]string, value float64) *sls.Log {

   now := uint32(time.Now().Unix())
   log := &sls.Log{Time: proto.Uint32(now)}

   var contents []*sls.LogContent
   contents = append(contents, &sls.LogContent{
      Key:   proto.String("__time_nano__"),
      Value: proto.String(strconv.FormatInt(int64(now), 10)),
   })
   contents = append(contents, &sls.LogContent{
      Key:   proto.String("__name__"),
      Value: proto.String(metricName),
   })
   contents = append(contents, &sls.LogContent{
      Key:   proto.String("__value__"),
      Value: proto.String(strconv.FormatFloat(value, 'f', 6, 64)),
   })

   keys := make([]string, 0, len(labels))
   for k := range labels {
      keys = append(keys, k)
   }
   sort.Strings(keys)

   labelsStr := ""
   for i, k := range keys {
      labelsStr += k
      labelsStr += "#$#"
      labelsStr += labels[k]
      if i < len(keys) - 1 {
         labelsStr += "|"
      }
   }

   contents = append(contents, &sls.LogContent{Key: proto.String("__labels__"), Value: proto.String(labelsStr)})
   log.Contents = contents
   return log

}

func main() {
   project := ""
   logstore := ""

   producerConfig := producer.GetDefaultProducerConfig()
   // The Simple Log Service endpoint. In this example, the Simple Log Service endpoint for the China (Hangzhou) region is used. Replace the parameter value with the actual endpoint. 
   producerConfig.Endpoint = "https://cn-hangzhou.log.aliyuncs.com"
   // Configure environment variables. In this example, the AccessKey ID and AccessKey secret are obtained from environment variables. 
   producerConfig.AccessKeyID = os.Getenv("ALIBABA_CLOUD_ACCESS_KEY_ID")
   producerConfig.AccessKeySecret = os.Getenv("ALIBABA_CLOUD_ACCESS_KEY_SECRET")
   producerInstance, err := producer.NewProducer(producerConfig)
   if err != nil {
     panic(err)
   }
   ch := make(chan os.Signal)
   signal.Notify(ch)
   producerInstance.Start()
   var m sync.WaitGroup
   for i := 0; i < 10; i++ {
      m.Add(1)
      go func() {
         defer m.Done()
         for i := 0; i < 1000; i++ {
            // GenerateLog  is producer's function for generating SLS format logs
            // GenerateLog has low performance, and native Log interface is the best choice for high performance.
            log := buildLogItem("test_metric", map[string]string{"test_k":"test_v"}, float64(i))
            err := producerInstance.SendLog(project, logstore, "topic", "127.0.0.1", log)
            if err != nil {
               fmt.Println(err)
            }
         }
      }()
   }
   m.Wait()
   fmt.Println("Send completion")
   if _, ok := <-ch; ok {
      fmt.Println("Get the shutdown signal and start to shut down")
      producerInstance.Close(60000)
   }
}