Repository: containerd/containerd
File: client/task.go (Go)

Code before:
	id  string
	pid uint32
}

// Spec returns the current OCI specification for the task
func (t *task) Spec(ctx context.Context) (*oci.Spec, error) {
	return t.c.Spec(ctx)
}

// ID of the task
func (t *task) ID() string {
	return t.id
}

// Pid returns the pid or process id for the task
func (t *task) Pid() uint32 {
	return t.pid
}

func (t *task) Start(ctx context.Context) error {
	ctx, span := tracing.StartSpan(ctx, tracing.Name("client.task", "Start"),
		tracing.WithAttribute("task.id", t.ID()))
	defer span.End()
	if ns, err := namespaces.NamespaceRequired(ctx); err == nil {
		span.SetAttributes(tracing.Attribute("containerd.namespace", ns))
	}

	r, err := t.client.TaskService().Start(ctx, &tasks.StartRequest{
		ContainerID: t.id,
	})
	if err != nil {
		if t.io != nil {
			t.io.Cancel()
			t.io.Close()
		}
		return errgrpc.ToNative(err)
	}
	span.SetAttributes(tracing.Attribute("task.pid", r.Pid))
	t.pid = r.Pid
	return nil
}

func (t *task) Kill(ctx context.Context, s syscall.Signal, opts ...KillOpts) error {
	_, span := tracing.StartSpan(ctx, tracing.Name("client.task", "Kill"),
		tracing.WithAttribute("task.id", t.ID()),
		tracing.WithAttribute("task.pid", int(t.Pid())),
	)
	defer span.End()
	if ns, err := namespaces.NamespaceRequired(ctx); err == nil {
		span.SetAttributes(tracing.Attribute("containerd.namespace", ns))
	}

Review comment (refactor):
This is used pretty often for spans, let's introduce a helper?
Something like:
```go
	ctx, span := tracing.StartSpan(ctx,
		tracing.Name("client.task", "Start"),
		tracing.WithAttribute("task.id", t.ID()),
		tracing.WithNamespace(ctx),
	)

...

> tracing.go

func WithNamespace(ctx context.Context) SpanOpt {
	return func(config *StartConfig) {
		if ns, err := namespaces.NamespaceRequired(ctx); err == nil {
			config.spanOpts = append(config.spanOpts,
				trace.WithAttributes(Attribute("containerd.namespace", ns)))
		}
	}
}
```

Code after:
	pid uint32
}

// Spec returns the current OCI specification for the task
func (t *task) Spec(ctx context.Context) (*oci.Spec, error) {
	return t.c.Spec(ctx)
}

// ID of the task
func (t *task) ID() string {
	return t.id
}

// Pid returns the pid or process id for the task
func (t *task) Pid() uint32 {
	return t.pid
}

func (t *task) Start(ctx context.Context) error {
	ctx, span := tracing.StartSpan(ctx, tracing.Name("client.task", "Start"),
		tracing.WithAttribute("task.id", t.ID()),
		tracing.WithNamespace(ctx),
	)
	defer span.End()

	r, err := t.client.TaskService().Start(ctx, &tasks.StartRequest{
		ContainerID: t.id,
	})
	if err != nil {
		if t.io != nil {
			t.io.Cancel()
			t.io.Close()
		}
		return errgrpc.ToNative(err)
	}
	span.SetAttributes(tracing.Attribute("task.pid", r.Pid))
	t.pid = r.Pid
	return nil
}

func (t *task) Kill(ctx context.Context, s syscall.Signal, opts ...KillOpts) error {
	ctx, span := tracing.StartSpan(ctx, tracing.Name("client.task", "Kill"),
		tracing.WithAttribute("task.id", t.ID()),
		tracing.WithAttribute("task.pid", int(t.Pid())),
		tracing.WithNamespace(ctx),
	)
	defer span.End()

	var i KillInfo
	for _, o := range opts {
		if err := o(ctx, &i); err != nil {