code: func (b *Bundler) Register(p *streamproto.Properties) (Stream, error) {
  	// Our Properties must validate.
  	if err := p.Validate(); err != nil {
  		return nil, err
  	}
  
  	// Enforce that the log stream descriptor's Prefix is empty.
  	p.Prefix = ""
  
  	// Construct a parser for this stream.
  	c := streamConfig{
  		name: p.Name,
  		template: logpb.ButlerLogBundle_Entry{
  			Desc: p.LogStreamDescriptor,
  		},
  		maximumBufferDuration: b.c.MaxBufferDelay,
  		maximumBufferedBytes:  b.c.MaxBufferedBytes,
  		onAppend: func(appended bool) {
  			if appended {
  				b.signalStreamUpdate()
  			}
  		},
  	}
  	if b.c.StreamRegistrationCallback != nil {
  		c.nextBundleEntryCallback = b.c.StreamRegistrationCallback(p.LogStreamDescriptor)
  	}
  
  	err := error(nil)
  	c.parser, err = newParser(p, &b.prefixCounter)
  	if err != nil {
  		return nil, fmt.Errorf("failed to create stream parser: %s", err)
  	}
  
  	b.streamsLock.Lock()
  	defer b.streamsLock.Unlock()
  
  	// Ensure that this is not a duplicate stream name.
  	if s := b.streams[p.Name]; s != nil {
  		return nil, fmt.Errorf("a Stream is already registered for %q", p.Name)
  	}
  
  	// Create a new stream. This will kick off its processing goroutine, which
  	// will not stop until it is closed.
  	s := newStream(c)
  	b.registerStreamLocked(s)
  	return s, nil
  }
docs: // Register adds a new stream to the Bundler, returning a reference to the
  // registered stream.
  //
  // The Bundler takes ownership of the supplied Properties, and may modify them
  // as needed.