Skip to content

Commit

Permalink
Add trace messages for automation
Browse files Browse the repository at this point in the history
Add a trace backend to linux/chip-tool which provides a simple
and flexible way to trace chip messages. The backend provides
handlers, which can be registered to handle the different
types of messages and extract the relevant data needed for
test automation.

Added additional optional flags to chip-tool which allows turning
on these traces and piping them either to a log or file. These
flags and tracing are only enabled when tracing is enabled at
compile time. Include trace compile with:
  gn gen out/with_trace/ --args='import("//with_pw_trace.gni")'

The trace point is before the encrypt in SecureMessageCodec and
only enabled when chip_enable_transport_trace is defined at compile
time and a pw_trace backend is configured.
  • Loading branch information
Rob Oliver committed Dec 9, 2021
1 parent a7dd25e commit 7658deb
Show file tree
Hide file tree
Showing 16 changed files with 677 additions and 21 deletions.
11 changes: 11 additions & 0 deletions examples/chip-tool/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ assert(chip_build_tools)
declare_args() {
# Use a separate eventloop for CHIP tasks
config_use_separate_eventloop = true
chip_enable_trace_chip = false
}

executable("chip-tool") {
Expand Down Expand Up @@ -68,5 +69,15 @@ executable("chip-tool") {
"${chip_root}/zzz_generated/chip-tool",
]

if (chip_enable_trace_chip) {
defines += [ "PW_TRACE_CHIP_ENABLED" ]

deps += [ "${chip_root}/examples/common/tracing:trace_handlers" ]
}

output_dir = root_out_dir
}

group("default") {
deps = [ ":chip-tool" ]
}
22 changes: 22 additions & 0 deletions examples/chip-tool/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,28 @@ scripts/examples/gn_build_example.sh examples/chip-tool SOME-PATH/

which puts the binary at `SOME-PATH/chip-tool`.

### Building with message tracing

Message tracing allows capture of the secure messages which can be used for test
automation.

```
gn gen out/with_trace/ --args='import("//with_pw_trace.gni")'
ninja -C out/with_trace chip-tool
```

This enables tracing and adds additional flags to chip-tool to control where the
traces should go:

- --trace_file <file> Outputs trace data to the specified file.
- --trace_log Outputs trace data to the chip log stream.

For example:

```
out/with_trace/chip-tool --trace_file trace.log pairing <pairing_args>
```

## Using the Client to commission a device

In order to send commands to a device, it must be commissioned with the client.
Expand Down
124 changes: 104 additions & 20 deletions examples/chip-tool/commands/common/Commands.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,80 @@
#include <lib/support/CHIPMem.h>
#include <lib/support/CodeUtils.h>

#include <lib/support/CHIPArgParser.hpp>

#ifdef PW_TRACE_CHIP_ENABLED
#include "TraceHandlers.h"

using namespace chip::trace;
#endif // PW_TRACE_CHIP_ENABLED

using namespace chip::ArgParser;

namespace {

#ifdef PW_TRACE_CHIP_ENABLED
enum
{
kOptionTraceFile = 0x1000,
kOptionTraceLog,
};

bool HandleTraceOptions(const char * program, OptionSet * options, int identifier, const char * name, const char * value)
{
switch (identifier)
{
case kOptionTraceLog:
SetTraceStream(new TraceStreamLog());
return true;
case kOptionTraceFile:
SetTraceStream(new TraceStreamFile(value));
return true;
default:
PrintArgError("%s: INTERNAL ERROR: Unhandled option: %s\n", program, name);
return false;
}
}

OptionDef traceCmdLineOptionDefs[] = { { "trace_file", kArgumentRequired, kOptionTraceFile },
{ "trace_log", kNoArgument, kOptionTraceLog },
{} };

const char * traceOptionHelp = " --trace_file <file>\n"
" Output trace data to the specified file.\n"
" --trace_log\n"
" Output trace data to the log stream.\n"
"\n";
OptionSet traceCmdLineOptions = { HandleTraceOptions, traceCmdLineOptionDefs, "TRACE OPTIONS", traceOptionHelp };
#endif // PW_TRACE_CHIP_ENABLED

const char * kAppName = "chip-tool";
const char * kUsage = "Usage: chip-tool [options] cluster command_name [param1] [param2]";
const char * kVersion = nullptr; // Unknown
const char * kDescription = "A command line tool that uses Matter to send messages to a Matter server.";
HelpOptions helpOptions(kAppName, kUsage, kVersion, kDescription);

OptionSet * allOptions[] = {
#ifdef PW_TRACE_CHIP_ENABLED
&traceCmdLineOptions,
#endif // PW_TRACE_CHIP_ENABLED
&helpOptions, nullptr
};

int gPositionalArgc = 0;
char ** gPositionalArgv = nullptr;
const char * gProgramName = nullptr;

bool GetPositionalArgs(const char * prog, int argc, char * argv[])
{
gProgramName = prog;
gPositionalArgc = argc;
gPositionalArgv = argv;
return true;
}

} // namespace

void Commands::Register(const char * clusterName, commands_list commandsList)
{
for (auto & command : commandsList)
Expand All @@ -46,71 +120,81 @@ int Commands::Run(int argc, char ** argv)

chip::Logging::SetLogFilter(mStorage.GetLoggingLevel());

err = RunCommand(argc, argv);
VerifyOrExit(ParseArgs("chip-tool", argc, argv, allOptions, GetPositionalArgs),
ChipLogError(chipTool, "Error parsing arguments"));

#ifdef PW_TRACE_CHIP_ENABLED
InitTrace();
#endif // PW_TRACE_CHIP_ENABLED

err = RunCommand();
VerifyOrExit(err == CHIP_NO_ERROR, ChipLogError(chipTool, "Run command failure: %s", chip::ErrorStr(err)));

exit:
#ifdef PW_TRACE_CHIP_ENABLED
DeInitTrace();
#endif // PW_TRACE_CHIP_ENABLED
return (err == CHIP_NO_ERROR) ? EXIT_SUCCESS : EXIT_FAILURE;
}

CHIP_ERROR Commands::RunCommand(int argc, char ** argv)
CHIP_ERROR Commands::RunCommand()
{
std::map<std::string, CommandsVector>::iterator cluster;
Command * command = nullptr;

if (argc <= 1)
if (gPositionalArgc <= 0)
{
ChipLogError(chipTool, "Missing cluster name");
ShowClusters(argv[0]);
ShowClusters(gProgramName);
return CHIP_ERROR_INVALID_ARGUMENT;
}

cluster = GetCluster(argv[1]);
cluster = GetCluster(gPositionalArgv[0]);
if (cluster == mClusters.end())
{
ChipLogError(chipTool, "Unknown cluster: %s", argv[1]);
ShowClusters(argv[0]);
ChipLogError(chipTool, "Unknown cluster: %s", gPositionalArgv[1]);
ShowClusters(gProgramName);
return CHIP_ERROR_INVALID_ARGUMENT;
}

if (argc <= 2)
if (gPositionalArgc <= 1)
{
ChipLogError(chipTool, "Missing command name");
ShowCluster(argv[0], argv[1], cluster->second);
ShowCluster(gProgramName, gPositionalArgv[0], cluster->second);
return CHIP_ERROR_INVALID_ARGUMENT;
}

if (!IsGlobalCommand(argv[2]))
if (!IsGlobalCommand(gPositionalArgv[1]))
{
command = GetCommand(cluster->second, argv[2]);
command = GetCommand(cluster->second, gPositionalArgv[1]);
if (command == nullptr)
{
ChipLogError(chipTool, "Unknown command: %s", argv[2]);
ShowCluster(argv[0], argv[1], cluster->second);
ChipLogError(chipTool, "Unknown command: %s", gPositionalArgv[1]);
ShowCluster(gProgramName, gPositionalArgv[0], cluster->second);
return CHIP_ERROR_INVALID_ARGUMENT;
}
}
else
{
if (argc <= 3)
if (gPositionalArgc <= 2)
{
ChipLogError(chipTool, "Missing attribute name");
ShowClusterAttributes(argv[0], argv[1], argv[2], cluster->second);
ShowClusterAttributes(gProgramName, gPositionalArgv[0], gPositionalArgv[1], cluster->second);
return CHIP_ERROR_INVALID_ARGUMENT;
}

command = GetGlobalCommand(cluster->second, argv[2], argv[3]);
command = GetGlobalCommand(cluster->second, gPositionalArgv[1], gPositionalArgv[2]);
if (command == nullptr)
{
ChipLogError(chipTool, "Unknown attribute: %s", argv[3]);
ShowClusterAttributes(argv[0], argv[1], argv[2], cluster->second);
ChipLogError(chipTool, "Unknown attribute: %s", gPositionalArgv[2]);
ShowClusterAttributes(gProgramName, gPositionalArgv[0], gPositionalArgv[1], cluster->second);
return CHIP_ERROR_INVALID_ARGUMENT;
}
}

if (!command->InitArguments(argc - 3, &argv[3]))
if (!command->InitArguments(gPositionalArgc - 2, &gPositionalArgv[2]))
{
ShowCommand(argv[0], argv[1], command);
ShowCommand(gProgramName, gPositionalArgv[0], command);
return CHIP_ERROR_INVALID_ARGUMENT;
}

Expand Down
3 changes: 2 additions & 1 deletion examples/chip-tool/commands/common/Commands.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ class Commands
int Run(int argc, char ** argv);

private:
CHIP_ERROR RunCommand(int argc, char ** argv);
CHIP_ERROR RunCommand();

std::map<std::string, CommandsVector>::iterator GetCluster(std::string clusterName);
Command * GetCommand(CommandsVector & commands, std::string commandName);
Command * GetGlobalCommand(CommandsVector & commands, std::string commandName, std::string attributeName);
Expand Down
29 changes: 29 additions & 0 deletions examples/chip-tool/with_pw_trace.gni
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Copyright (c) 2021 Project CHIP Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# add this gni as import in your build args to use pigweed in the example
# 'import("//with_pw_rpc.gni")'

import("//build_overrides/chip.gni")

import("${chip_root}/config/standalone/args.gni")

import("//build_overrides/pigweed.gni")

cpp_standard = "gnu++17"

pw_trace_BACKEND = "${chip_root}/examples/platform/linux/pw_trace_chip"

chip_enable_trace_chip = true
chip_enable_transport_trace = true
35 changes: 35 additions & 0 deletions examples/common/tracing/BUILD.gn
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Copyright (c) 2021 Project CHIP Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import("//build_overrides/pigweed.gni")

import("//build_overrides/build.gni")
import("//build_overrides/chip.gni")
import("$dir_pw_build/target_types.gni")
import("${chip_root}/src/lib/lib.gni")

config("default_config") {
include_dirs = [ "." ]
}

source_set("trace_handlers") {
sources = [ "TraceHandlers.cpp" ]

deps = [
"$dir_pw_trace",
"${chip_root}/src/lib",
]

public_configs = [ ":default_config" ]
}
5 changes: 5 additions & 0 deletions examples/common/tracing/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Trace Handlers

These are trace message handlers which get registered with pw_trace_chip and
interpret the different CHIP messages to extract the useful information required
for test automation.
Loading

0 comments on commit 7658deb

Please sign in to comment.