### Start Transaction with Options Source: https://github.com/elastic/apm-agent-go/blob/main/docs/reference/api-documentation.md Start a transaction with additional options, such as specifying the parent trace context or the transaction's start time. ```go opts := apm.TransactionOptions{ Start: time.Now(), TraceContext: parentTraceContext, } transaction := apm.DefaultTracer().StartTransactionOptions("GET /", "request", opts) ``` -------------------------------- ### Tracer.StartTransactionOptions Source: https://github.com/elastic/apm-agent-go/blob/main/docs/reference/api-documentation.md Starts a new transaction with options, allowing specification of start time and parent trace context. ```APIDOC ## Tracer.StartTransactionOptions ### Description Starts a new transaction with the specified name, type, and options. This allows for setting a custom start time and a parent trace context. ### Method `func (*Tracer) StartTransactionOptions(name, type string, opts TransactionOptions) *Transaction` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```go opts := apm.TransactionOptions{ Start: time.Now(), TraceContext: parentTraceContext, } transaction := apm.DefaultTracer().StartTransactionOptions("GET /", "request", opts) ``` ### Response #### Success Response Returns a pointer to a `Transaction` object. #### Response Example (No specific response example provided in source, returns *Transaction) ``` -------------------------------- ### Set Global Tracer and Start Spans Source: https://github.com/elastic/apm-agent-go/blob/main/docs/reference/opentracing-api.md Set the global OpenTracing tracer and demonstrate starting parent and child spans from context. ```go import ( "context" "go.elastic.co/apm/module/apmot/v2" "github.com/opentracing/opentracing-go" ) func main() { opentracing.SetGlobalTracer(apmot.New()) parent, ctx := opentracing.StartSpanFromContext(context.Background(), "parent") child, _ := opentracing.StartSpanFromContext(ctx, "child") child.Finish() parent.Finish() } ``` -------------------------------- ### Start a Span with Options Source: https://github.com/elastic/apm-agent-go/blob/main/docs/reference/api-documentation.md This method is similar to StartSpan but allows specifying the parent trace context and/or the span's start time. If no parent is specified, the span becomes a direct child of the transaction. ```go opts := apm.SpanOptions{ Start: time.Now(), Parent: parentSpan.TraceContext(), } span := tx.StartSpanOptions("SELECT FROM foo", "db.mysql.query", opts) ``` -------------------------------- ### Install Elastic APM Go Agent Source: https://github.com/elastic/apm-agent-go/blob/main/docs/reference/set-up-apm-go-agent.md Install the Elastic APM Go agent package within a Go module using the go get command. ```bash go get -u go.elastic.co/apm/v2 ``` -------------------------------- ### Start a Span from Context Source: https://github.com/elastic/apm-agent-go/blob/main/docs/reference/api-documentation.md Starts a new span within the sampled transaction and parent span found in the context. If the span is not dropped, it's included in the resulting context. ```go span, ctx := apm.StartSpan(ctx, "SELECT FROM foo", "db.mysql.query") ``` -------------------------------- ### Start and End a Transaction Source: https://github.com/elastic/apm-agent-go/blob/main/docs/reference/custom-instrumentation.md Start a new transaction with a name and type, customize it with context, and end it. Use defer tx.End() to ensure the transaction is always ended. ```go tx := apm.DefaultTracer().StartTransaction("GET /api/v1", "request") defer tx.End() ... tx.Result = "HTTP 2xx" tx.Context.SetLabel("region", "us-east-1") ``` -------------------------------- ### Transaction.StartSpanOptions Source: https://github.com/elastic/apm-agent-go/blob/main/docs/reference/api-documentation.md Starts a new Span with additional options, allowing specification of the parent trace context and start time. If no parent is specified, the span becomes a direct child of the transaction. ```APIDOC ## Transaction.StartSpanOptions ### Description StartSpanOptions is essentially the same as StartSpan, but also accepts an options struct. This struct allows you to specify the parent trace context and/or the spans’s start time. If the parent trace context is not specified in the options, then the span will be a direct child of the transaction. Otherwise, the parent trace context should belong to some span descended from the transaction. ### Method Signature `func (*Transaction) StartSpanOptions(name, spanType string, opts SpanOptions) *Span` ### Parameters - **name** (string) - The name of the span. - **spanType** (string) - The type of the span. - **opts** (SpanOptions) - A struct containing options like Start time and Parent trace context. - **Start** (time.Time) - The start time of the span. - **Parent** (TraceContext) - The parent trace context. ### Example ```go opts := apm.SpanOptions{ Start: time.Now(), Parent: parentSpan.TraceContext(), } span := tx.StartSpanOptions("SELECT FROM foo", "db.mysql.query", opts) ``` ``` -------------------------------- ### Start a new Span within a Transaction Source: https://github.com/elastic/apm-agent-go/blob/main/docs/reference/api-documentation.md Use this method to start a new span with a name, type, and optional parent. The span's start time is set to the current time. If the transaction is not sampled, the span will be discarded. ```go span := tx.StartSpan("SELECT FROM foo", "db.mysql.query", nil) ``` -------------------------------- ### Example Log Message with Trace IDs Source: https://github.com/elastic/apm-agent-go/blob/main/docs/reference/log-correlation.md An example of an unstructured log message that includes trace, transaction, and span IDs, formatted for easy parsing. ```text 2019/09/17 14:48:02 ERROR [trace.id=cd04f33b9c0c35ae8abe77e799f126b7 transaction.id=cd04f33b9c0c35ae span.id=960834f4538880a4] an error occurred ``` -------------------------------- ### Tracer.StartTransaction Source: https://github.com/elastic/apm-agent-go/blob/main/docs/reference/api-documentation.md Starts a new transaction with a given name and type. This is the primary method to begin tracking a request or operation. ```APIDOC ## Tracer.StartTransaction ### Description Starts a new transaction with the specified name and type. The transaction's start time is set to the current time. Use `StartTransactionOptions` for custom timestamps or parent trace contexts. ### Method `func (*Tracer) StartTransaction(name, type string) *Transaction` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```go transaction := apm.DefaultTracer().StartTransaction("GET /", "request") ``` ### Response #### Success Response Returns a pointer to a `Transaction` object. #### Response Example (No specific response example provided in source, returns *Transaction) ``` -------------------------------- ### Wrap SQL Drivers with apmsql Source: https://github.com/elastic/apm-agent-go/blob/main/docs/reference/builtin-modules.md Register and open SQL drivers using apmsql to trace queries as spans. This example shows registration for PostgreSQL and SQLite. ```go import ( "go.elastic.co/apm/module/apmsql/v2" _ "go.elastic.co/apm/module/apmsql/v2/pq" _ "go.elastic.co/apm/module/apmsql/v2/sqlite3" ) func main() { db, err := apmsql.Open("postgres", "postgres://...") db, err := apmsql.Open("sqlite3", ":memory:") } ``` -------------------------------- ### Start a Transaction Source: https://github.com/elastic/apm-agent-go/blob/main/docs/reference/api-documentation.md Start a new transaction with a given name and type. This should be called at the beginning of a request or operation. Transactions are grouped by type and name in the Elastic APM app. ```go transaction := apm.DefaultTracer().StartTransaction("GET /", "request") ``` -------------------------------- ### Example of apmslog Handler Usage Source: https://github.com/elastic/apm-agent-go/blob/main/docs/reference/builtin-modules.md Demonstrates how to create and use the apmslog Handler with slog. It shows how to configure the handler to send logs to Elastic APM and how trace context is automatically attached to log messages when using context-aware logging methods. ```go import ( "context" "log/slog" "go.elastic.co/apm/module/apmslog/v2" ) func ExampleHandler() { // Report slog "ERROR" level messages to Elastic APM using // apm.DefaultTracer() while utilizing some specific slog handler // to format logging messages apmHandler = apmslog.NewApmHandler( apmslog.WithHandler( slog.NewJSONHandler(os.Stderr, &slog.HandlerOptions{ Level: slog.LevelInfo, }), ), ) logger = slog.New(apmHandler) // while using slog context aware methods, any existing trace, // transaction, or span ID are added from the given context tx := apm.DefaultTracer().StartTransaction("name", "type") defer tx.End() ctx := apm.ContextWithTransaction(context.Background(), tx) span, ctx := apm.StartSpan(ctx, "name", "type") defer span.End() // log msg will have a trace, transaction, and a span attached logger.InfoContext(ctx, "I should have a trace, transaction, and span id attached!") // the log msg will be reported to apm logger.ErrorContext(ctx, "I want this to be reported, but have no error to attach") // the log msg with its error will be reported to apm logger.ErrorContext(ctx, "I will report this error to apm", "error", errors.New("new error")) // BOTH errors with the log msg will be reported to apm. [ error, err ] slog attribute keys are by default reported logger.ErrorContext(ctx, "I will report this error to apm", "error", errors.New("new error"), "err", errors.New("new err")) } ``` -------------------------------- ### apm.StartSpan Source: https://github.com/elastic/apm-agent-go/blob/main/docs/reference/api-documentation.md Starts a new Span within the sampled transaction and parent span found in the context. If the span is not dropped, it is included in the resulting context. ```APIDOC ## apm.StartSpan ### Description StartSpan starts and returns a new Span within the sampled transaction and parent span in the context, if any. If the span isn’t dropped, it will be included in the resulting context. ### Method Signature `func StartSpan(ctx context.Context, name, spanType string) (*Span, context.Context)` ### Parameters - **ctx** (context.Context) - The current context. - **name** (string) - The name of the span. - **spanType** (string) - The type of the span. ### Returns - **(*Span, context.Context)** - The created span and the updated context. ### Example ```go span, ctx := apm.StartSpan(ctx, "SELECT FROM foo", "db.mysql.query") ``` ``` -------------------------------- ### Transaction.StartSpan Source: https://github.com/elastic/apm-agent-go/blob/main/docs/reference/api-documentation.md Starts a new Span within the current transaction. It takes a name, type, and an optional parent span. The span's start time is set to the current time. If the transaction is not sampled, the span will be discarded. ```APIDOC ## Transaction.StartSpan ### Description Starts and returns a new Span within the transaction, with the specified name, type, and optional parent span, and with the start time set to the current time. If you need to set the timestamp or parent trace context, use Transaction.StartSpanOptions. If the span type contains two dots, they are assumed to separate the span type, subtype, and action; a single dot separates span type and subtype, and the action will not be set. If the transaction is sampled, then the span’s ID will be set, and its stacktrace will be set if the tracer is configured accordingly. If the transaction is not sampled, then the returned span will be silently discarded when its End method is called. To avoid any unnecessary computation for these dropped spans, call the Dropped method. As a convenience, it is valid to create a span on a nil Transaction; the resulting span will be non-nil and safe for use, but will not be reported to the APM server. ### Method Signature `func (*Transaction) StartSpan(name, spanType string, parent *Span) *Span` ### Parameters - **name** (string) - The name of the span. - **spanType** (string) - The type of the span (e.g., "db.mysql.query"). - **parent** (*Span) - Optional parent span. ### Example ```go span := tx.StartSpan("SELECT FROM foo", "db.mysql.query", nil) ``` ``` -------------------------------- ### Beego Middleware and Span Creation Source: https://github.com/elastic/apm-agent-go/blob/main/docs/reference/builtin-modules.md Provides middleware for the Beego web framework and demonstrates starting a span within a controller. The apmbeego middleware handles request transactions and panics. ```go import ( "github.com/astaxie/beego" "go.elastic.co/apm/v2" "go.elastic.co/apm/module/apmbeego/v2" ) type thingController struct{beego.Controller} func (c *thingController) Get() { span, _ := apm.StartSpan(c.Ctx.Request.Context(), "thingController.Get", "controller") span.End() ... } func main() { beego.Router("/", &thingController{}) beego.Router("/thing/:id:int", &thingController{}, "get:Get") beego.RunWithMiddleWares("localhost:8080", apmbeego.Middleware()) } ``` -------------------------------- ### Start and End a Span Source: https://github.com/elastic/apm-agent-go/blob/main/docs/reference/custom-instrumentation.md Start a span within a transaction to represent a sub-operation. Use defer span.End() to ensure the span is always ended. The span can be associated with a parent span if one exists in the context. ```go span, ctx := apm.StartSpan(ctx, "SELECT FROM foo", "db.mysql.query") defer span.End() ``` -------------------------------- ### Instrumenting HTTP Handlers and Database Queries Source: https://github.com/elastic/apm-agent-go/blob/main/docs/reference/custom-instrumentation-propagation.md This example demonstrates how to instrument an HTTP handler to create a transaction and how to create child spans for database queries using apmsql. The transaction is automatically added to the request context by apmhttp.Wrap, and this context is passed down to functions like getList to create child spans. ```go import ( "context" "database/sql" "net/http" "go.elastic.co/apm/v2" "go.elastic.co/apm/module/apmhttp/v2" "go.elastic.co/apm/module/apmsql/v2" _ "go.elastic.co/apm/module/apmsql/v2/pq" ) var db *sql.DB func init() { // apmsql.Open wraps sql.Open, // in order to add tracing to database operations. db, _ = apmsql.Open("postgres", "") } func main() { mux := http.NewServeMux() mux.HandleFunc("/", handleList) // apmhttp.Wrap instruments an http.Handler, in order // to report any request to this handler as a transaction, // and to store the transaction in the request's context. handler := apmhttp.Wrap(mux) http.ListenAndServe(":8080", handler) } func handleList(w http.ResponseWriter, req *http.Request) { // By passing the request context down to getList, getList can add spans to it. ctx := req.Context() getList(ctx) // ... } func getList(ctx context.Context) ( // When getList is called with a context containing a transaction or span, // StartSpan creates a child span. In this example, getList is always called // with a context containing a transaction for the handler, so we should // expect to see something like: // // Transaction: handleList // Span: getList // Span: SELECT FROM items // span, ctx := apm.StartSpan(ctx, "getList", "custom") defer span.End() // NOTE: The context object ctx returned by StartSpan above contains // the current span now, so subsequent calls to StartSpan create new // child spans. // db was opened with apmsql, so queries will be reported as // spans when using the context methods. rows, err := db.QueryContext(ctx, "SELECT * FROM items") // ... rows.Close() ) ``` -------------------------------- ### Get Default Tracer Source: https://github.com/elastic/apm-agent-go/blob/main/docs/reference/api-documentation.md Obtain the default APM tracer. The tracer is initialized on the first call to DefaultTracer() and configured via environment variables. ```go import ( "go.elastic.co/apm/v2" ) func main() { tracer := apm.DefaultTracer() ... ``` -------------------------------- ### Inject Trace Context for RUM Initialization Source: https://github.com/elastic/apm-agent-go/blob/main/docs/reference/api-documentation.md Example of injecting trace and parent span IDs into an HTML template to initialize the JavaScript RUM agent. This ensures the page load appears as the root of the trace. ```go var initialPageTemplate = template.Must(template.New("").Parse(`
... `)) func initialPageHandler(w http.ResponseWriter, req *http.Request) { err := initialPageTemplate.Execute(w, apm.TransactionFromContext(req.Context())) if err != nil { ... } } ``` -------------------------------- ### Get Span Trace Context Source: https://github.com/elastic/apm-agent-go/blob/main/docs/reference/api-documentation.md Returns the span's trace context, which can be used to set the parent for new spans. ```go span.TraceContext() ``` -------------------------------- ### apm.ContextWithSpan Source: https://github.com/elastic/apm-agent-go/blob/main/docs/reference/api-documentation.md Adds a span to the provided context and returns the updated context. This span can later be retrieved using SpanFromContext or used as a parent for new spans started with apm.StartSpan. ```APIDOC ## apm.ContextWithSpan ### Description ContextWithSpan adds the span to the context and returns the resulting context. The span can be retrieved using apm.SpanFromContext. The context may also be passed into apm.StartSpan, which uses SpanFromContext under the covers to create another span as a child of the span. ### Method Signature `func ContextWithSpan(context.Context, *Span) context.Context` ### Parameters - **ctx** (context.Context) - The original context. - **span** (*Span) - The span to add to the context. ### Returns - **context.Context** - The context with the span added. ``` -------------------------------- ### Run Go Test Suite Source: https://github.com/elastic/apm-agent-go/blob/main/CONTRIBUTING.md Execute the entire test suite for the project. This command should be run to ensure no existing functionality is broken by your changes. ```bash go test ./... ``` -------------------------------- ### Initialize and Configure OpenTelemetry Tracing Source: https://github.com/elastic/apm-agent-go/blob/main/docs/reference/opentelemetry-api.md Set up the OpenTelemetry Tracer Provider and create a span. Spans created here will be sent to the Elastic APM tracer. ```go import ( "go.elastic.co/apm/v2" "go.elastic.co/apm/module/apmotel/v2" "go.opentelemetry.io/otel" ) func main() { provider, err := apmotel.NewTracerProvider() if err != nil { log.Fatal(err) } otel.SetTracerProvider(provider) racer := otel.GetTracerProvider().Tracer("example") // Start a new span to track some work, which will be sent to the Elastic APM tracer ctx, span := tracer.Start(context.Background(), "my_work") // Do something span.End() } ``` -------------------------------- ### Initialize and Configure OpenTelemetry Metrics Source: https://github.com/elastic/apm-agent-go/blob/main/docs/reference/opentelemetry-api.md Set up the OpenTelemetry MeterProvider with the custom exporter and register the exporter with the Elastic APM agent. Metrics recorded via OpenTelemetry will be exported to the Elastic Agent. ```go import ( "go.elastic.co/apm" "go.elastic.co/apm/module/apmotel" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/sdk/metric" ) func main() { exporter := apmotel.NewGatherer() // Configure OpenTelemetry provider := metric.NewMeterProvider(metric.WithReader(exporter)) otel.SetMeterProvider(provider) // Configure the Elastic APM apm.DefaultTracer().RegisterMetricsGatherer(exporter) // Record a metric with OpenTelemetry which will be exported to the Elastic Agent meter := provider.Meter("my_application") counter, _ := meter.Float64Counter("metric_called") counter.Add(context.TODO(), 1) } ``` -------------------------------- ### Initialize OpenTracing Tracer Source: https://github.com/elastic/apm-agent-go/blob/main/docs/reference/opentracing-api.md Initialize the OpenTracing tracer using apmot.New(). It wraps apm.DefaultTracer() by default, or a custom tracer can be provided. ```go otTracer := apmot.New() ``` -------------------------------- ### Create OpenTelemetry Tracer Provider Source: https://github.com/elastic/apm-agent-go/blob/main/docs/reference/opentelemetry-api.md Instantiate the OpenTelemetry Tracer Provider using apmotel.NewTracerProvider. ```go provider, err := apmotel.NewTracerProvider() ``` -------------------------------- ### Initialize GORM v2 with Elastic APM Tracing Source: https://github.com/elastic/apm-agent-go/blob/main/module/apmgormv2/README.md Replace the standard GORM driver import with the Elastic APM driver for MySQL. This enables automatic tracing of database operations. ```go import ( mysql "go.elastic.co/apm/module/apmgormv2/driver/mysql" "gorm.io/gorm" ) db, err := gorm.Open(mysql.Open("dsn"), &gorm.Config{}) ``` -------------------------------- ### Import OpenTelemetry Tracing Bridge Package Source: https://github.com/elastic/apm-agent-go/blob/main/docs/reference/opentelemetry-api.md Import the apmotel package to use the OpenTelemetry tracing bridge. ```go import ( "go.elastic.co/apm/module/apmotel/v2" ) ``` -------------------------------- ### Mixing Native and OpenTracing APIs Source: https://github.com/elastic/apm-agent-go/blob/main/docs/reference/opentracing-api.md Demonstrates creating a transaction with the native API and then a child span using the OpenTracing API, followed by another native API span as a child of the OpenTracing span. ```go // Transaction created through native API. transaction := apm.DefaultTracer().StartTransaction("GET /", "request") ctx := apm.ContextWithTransaction(context.Background(), transaction) // Span created through OpenTracing API will be a child of the transaction. otSpan, ctx := opentracing.StartSpanFromContext(ctx, "ot-span") // Span created through the native API will be a child of the span created // above via the OpenTracing API. apmSpan, ctx := apm.StartSpan(ctx, "apm-span", "apm-span") ``` -------------------------------- ### Set Transaction on Error Source: https://github.com/elastic/apm-agent-go/blob/main/docs/reference/api-documentation.md Associates an error with an active transaction. Ensure the transaction is started before creating the error. ```go tx := apm.DefaultTracer().StartTransaction("GET /foo", "request") defer tx.End() e := apm.DefaultTracer().NewError(err) e.SetTransaction(tx) e.Send() ``` -------------------------------- ### Get Span Parent ID Source: https://github.com/elastic/apm-agent-go/blob/main/docs/reference/api-documentation.md Returns the ID of the span's parent. This is useful for understanding the span hierarchy. ```go span.ParentID() ``` -------------------------------- ### Get Transaction Trace Context Source: https://github.com/elastic/apm-agent-go/blob/main/docs/reference/api-documentation.md Retrieve the transaction's trace context, which includes trace and span IDs. ```go transaction.TraceContext() ``` -------------------------------- ### Import apmot package Source: https://github.com/elastic/apm-agent-go/blob/main/docs/reference/opentracing-api.md Import the apmot package to use the OpenTracing API implementation. ```go import ( "go.elastic.co/apm/module/apmot/v2" ) ``` -------------------------------- ### Import OpenTelemetry Metrics Exporter Package Source: https://github.com/elastic/apm-agent-go/blob/main/docs/reference/opentelemetry-api.md Import the apmotel package to use the OpenTelemetry metrics exporter. ```go import ( "go.elastic.co/apm/module/apmotel" ) ``` -------------------------------- ### Get Transaction Parent ID Source: https://github.com/elastic/apm-agent-go/blob/main/docs/reference/api-documentation.md Retrieve the ID of the transaction's parent span. Returns a zero (invalid) SpanID if the transaction has no parent. ```go transaction.ParentID() ``` -------------------------------- ### Create GitHub Release Source: https://github.com/elastic/apm-agent-go/blob/main/CONTRIBUTING.md Creates a new release on GitHub using the GitHub CLI. This is a step in the release procedure after creating tags. ```bash gh release create vN.N.N ``` -------------------------------- ### Span.End Source: https://github.com/elastic/apm-agent-go/blob/main/docs/reference/api-documentation.md Marks the span as complete. The span's duration is calculated from its start time to this call. The duration can be overridden by setting the Duration field before calling End. ```APIDOC ## Span.End ### Description End marks the span as complete. The Span must not be modified after this, but may still be used as the parent of a span. The span’s duration will be calculated as the amount of time elapsed since the span was started until this call. To override this behaviour, the span’s Duration field may be set before calling End. ### Method Signature `func (*Span) End()` ``` -------------------------------- ### End a Span Source: https://github.com/elastic/apm-agent-go/blob/main/docs/reference/api-documentation.md Marks the span as complete. The span's duration is calculated from its start time to this call. The duration can be overridden by setting the Duration field before calling End. ```go span.End() ``` -------------------------------- ### Import apmlambda for AWS Lambda Tracing Source: https://github.com/elastic/apm-agent-go/blob/main/docs/reference/builtin-modules.md Importing this package is sufficient to automatically report AWS Lambda function invocations. Future versions may require explicit calls to apmlambda.Start. ```go import ( _ "go.elastic.co/apm/module/apmlambda/v2" ) ``` -------------------------------- ### Check Test Coverage Source: https://github.com/elastic/apm-agent-go/blob/main/CONTRIBUTING.md Run the test suite and report code coverage. This helps ensure that your new or modified code is adequately tested. ```bash go test -cover ``` -------------------------------- ### Ensure Parent Span ID for RUM Integration Source: https://github.com/elastic/apm-agent-go/blob/main/docs/reference/api-documentation.md Get the transaction's parent span ID, generating one if it doesn't exist. This is useful for correlating backend traces with frontend JavaScript RUM agent data. ```go transaction.EnsureParent() ``` -------------------------------- ### Update Go Modules Source: https://github.com/elastic/apm-agent-go/blob/main/CONTRIBUTING.md Synchronizes dependencies and updates module information. This command is part of the release procedure. ```bash make update-modules ``` -------------------------------- ### Instrument GORM Database Operations Source: https://github.com/elastic/apm-agent-go/blob/main/docs/reference/builtin-modules.md Import apmgorm/dialects and use apmgorm.Open and apmgorm.WithContext to instrument GORM operations. This creates spans for database queries. ```go import ( "go.elastic.co/apm/module/apmgorm/v2" _ "go.elastic.co/apm/module/apmgorm/v2/dialects/postgres" ) func main() { db, err := apmgorm.Open("postgres", "") ... db = apmgorm.WithContext(ctx, db) db.Find(...) // creates a "SELECT FROM