Home

Awesome

CircleCI
License: MIT

go-structurizr

This library allows you to auto-generate C4 component diagrams from Go code.

Example

Usage and Examples

To quickly learn how to use the library, check out my blog post for a step-by-step implementation guide.

You can also find several examples in the cmd directory. To run any of these examples, use the provided shell script.

How It Works

The library provides tools (Scraper and View) to scrape and render Go structures into a C4 component diagram in PlantUML format.

Scraper identifies components to scrape under the following conditions:

Components

Component Info

The model.Info structure defines a component in the scraped structure of your code:

type Info struct {
	Kind        string      // kind of scraped component
	Name        string      // component name
	Description string      // component description
	Technology  string      // technology used within the component
	Tags        []string    // tags used to match view styles to component
}

Scraper

You can instantiate the scraper in one of two ways:

To instantiate the scraper, provide a configuration that includes the prefixes of packages you want to reflect. Types that do not match any of the specified prefixes will not be processed.

config := scraper.NewConfiguration(
    "github.com/org/pkg",
)
s := scraper.NewScraper(config)

After creating a scraper instance, you can register rules that will allow it to identify components to include in the output structure.

Each rule consists of:

r, err := scraper.NewRule().
    WithPkgRegexps("github.com/org/pkg/foo/.*").
    WithNameRegexp("^.*Client$").
    WithApplyFunc(
        func(name string, _ ...string) model.Info {
            return model.ComponentInfo(name, "foo client", "gRPC", "TAG")
        }).
    Build()
err = s.RegisterRule(r)

The apply function has two arguments: the name and groups matched from the name regular expression.

Example:

r, err := scraper.NewRule().
    WithPkgRegexps("github.com/org/pkg/foo/.*").
    WithNameRegexp(`^(\w*)\.(\w*)Client$`).
    WithApplyFunc(
        func(_ string, groups ...string) model.Info {
            // Perform checks on the groups, then:
            n := fmt.Sprintf("Client of external %s service", groups[1])
            return model.ComponentInfo(n, "foo client", "gRPC", "TAG")
        }).
    Build()
err = s.RegisterRule(r)

Alternatively, you can instantiate the scraper from a YAML configuration file:

# go-structurizr.yml
configuration:
  pkgs:
    - "github.com/org/pkg"

rules:
  - name_regexp: "^.*Client$"
    pkg_regexps:
      - "github.com/org/pkg/foo/.*"
    component:
      description: "foo client"
      technology: "gRPC"
      tags:
        - TAG

You can also use regular expression groups in YAML rule definitions:

rules:
  - name_regexp: "(\\w*)\\.(\\w*)Client$"
    pkg_regexps:
      - "github.com/org/pkg/foo/.*"
    component:
      name: "Client of external {1} service"
      description: "foo client"
      technology: "gRPC"
      tags:
        - TAG

To create a scraper from the configuration file:

s, err := scraper.NewScraperFromConfigFile("./go-structurizr.yml")

Once the scraper is instantiated and configured, you can use it to scrape any structure. The scraper returns a model.Structure.

structure := s.Scrape(app)

View

Similarly to the scraper, a view can be instantiated in one of two ways:

To render a scraped structure, you need to instantiate and configure a view. A view consists of:

To instantiate a default view, use the view builder:

v := view.NewView().Build()

To customize it, use the available builder methods:

v := view.NewView().
    WithTitle("Title").
    WithComponentStyle(
        view.NewComponentStyle("TAG").
            WithBackgroundColor(color.White).
            WithFontColor(color.Black).
            WithBorderColor(color.Black).
            WithShape("database").
            Build(),
    ).
    WithComponentTag("TAG").
    WithRootComponentTag("ROOT").
    Build()

Alternatively, you can instantiate the view from a YAML configuration file:

# go-structurizr.yml
view:
  title: "Title"
  line_color: 000000ff
  styles:
    - id: TAG
      background_color: ffffffff
      font_color: 000000ff
      border_color: 000000ff
      shape: database
  root_component_tags:
    - ROOT
  component_tags:
    - TAG

To create a view from the configuration file:

v, err := view.NewViewFromConfigFile("./go-structurizr.yml")

Once the view is initialized, you can render the structure into a PlantUML diagram:

outFile, _ := os.Create("c4.plantuml")
defer func() {
    _ = outFile.Close()
}()

err = v.RenderStructureTo(structure, outFile)

Debug Mode

To enable detailed scraping or view rendering logs, set the LOG_LEVEL environment variable to debug or DEBUG.

Best Practices

For the best results and experience with the library, follow these practices:

Full Code Documentation

For full code documentation, visit pkg.go.dev.